@@ -252,7 +252,7 @@ protected override Expression VisitExtension(Expression extensionExpression)
252252 var alias = _aliasManager . GenerateSourceAlias ( fromSql ) ;
253253 var selectExpression = new SelectExpression (
254254 new SourceExpression ( fromSql , alias ) ,
255- new EntityProjectionExpression ( new ObjectReferenceExpression ( entityType , alias ) , entityType ) ) ;
255+ new StructuralTypeProjectionExpression ( new ObjectReferenceExpression ( entityType , alias ) , entityType ) ) ;
256256 return CreateShapedQueryExpression ( entityType , selectExpression ) ?? QueryCompilationContext . NotTranslatedExpression ;
257257
258258 default :
@@ -300,7 +300,7 @@ protected override QueryableMethodTranslatingExpressionVisitor CreateSubqueryVis
300300 var alias = _aliasManager . GenerateSourceAlias ( "c" ) ;
301301 var selectExpression = new SelectExpression (
302302 new SourceExpression ( new ObjectReferenceExpression ( entityType , "root" ) , alias ) ,
303- new EntityProjectionExpression ( new ObjectReferenceExpression ( entityType , alias ) , entityType ) ) ;
303+ new StructuralTypeProjectionExpression ( new ObjectReferenceExpression ( entityType , alias ) , entityType ) ) ;
304304
305305 // Add discriminator predicate
306306 var concreteEntityTypes = entityType . GetConcreteDerivedTypesInclusive ( ) . ToList ( ) ;
@@ -323,7 +323,7 @@ protected override QueryableMethodTranslatingExpressionVisitor CreateSubqueryVis
323323 "Missing discriminator property in hierarchy" ) ;
324324 if ( discriminatorProperty is not null )
325325 {
326- var discriminatorColumn = ( ( EntityProjectionExpression ) selectExpression . GetMappedProjection ( new ProjectionMember ( ) ) )
326+ var discriminatorColumn = ( ( StructuralTypeProjectionExpression ) selectExpression . GetMappedProjection ( new ProjectionMember ( ) ) )
327327 . BindProperty ( discriminatorProperty , clientEval : false ) ;
328328
329329 var success = TryApplyPredicate (
@@ -340,9 +340,9 @@ protected override QueryableMethodTranslatingExpressionVisitor CreateSubqueryVis
340340 return CreateShapedQueryExpression ( entityType , selectExpression ) ;
341341 }
342342
343- private ShapedQueryExpression ? CreateShapedQueryExpression ( IEntityType entityType , SelectExpression queryExpression )
343+ private ShapedQueryExpression ? CreateShapedQueryExpression ( ITypeBase structuralType , SelectExpression queryExpression )
344344 {
345- if ( ! entityType . IsOwned ( ) )
345+ if ( structuralType is IEntityType entityType && ! entityType . IsOwned ( ) )
346346 {
347347 var existingEntityType = _queryCompilationContext . RootEntityType ;
348348 if ( existingEntityType is not null && existingEntityType != entityType )
@@ -358,7 +358,7 @@ protected override QueryableMethodTranslatingExpressionVisitor CreateSubqueryVis
358358 return new ShapedQueryExpression (
359359 queryExpression ,
360360 new StructuralTypeShaperExpression (
361- entityType ,
361+ structuralType ,
362362 new ProjectionBindingExpression ( queryExpression , new ProjectionMember ( ) , typeof ( ValueBuffer ) ) ,
363363 nullable : false ) ) ;
364364 }
@@ -532,6 +532,14 @@ protected override ShapedQueryExpression TranslateCast(ShapedQueryExpression sou
532532 return null ;
533533 }
534534
535+ // We can not apply distinct because SQL DISTINCT operates on the full
536+ // structural type, but the shaper extracts only a subset of that data.
537+ // Cosmos: Projecting out nested documents retrieves the entire document #34067
538+ if ( select . UsesClientProjection )
539+ {
540+ return null ;
541+ }
542+
535543 select . ApplyDistinct ( ) ;
536544
537545 return source ;
@@ -607,7 +615,7 @@ protected override ShapedQueryExpression TranslateCast(ShapedQueryExpression sou
607615
608616 var translatedSelect =
609617 new SelectExpression (
610- new EntityProjectionExpression ( translation , ( IEntityType ) projectedStructuralTypeShaper . StructuralType ) ) ;
618+ new StructuralTypeProjectionExpression ( translation , projectedStructuralTypeShaper . StructuralType ) ) ;
611619 return source . Update (
612620 translatedSelect ,
613621 new StructuralTypeShaperExpression (
@@ -859,24 +867,19 @@ protected override ShapedQueryExpression TranslateCast(ShapedQueryExpression sou
859867 /// </summary>
860868 protected override ShapedQueryExpression ? TranslateOfType ( ShapedQueryExpression source , Type resultType )
861869 {
862- if ( source . ShaperExpression is not StructuralTypeShaperExpression entityShaperExpression )
870+ if ( source . ShaperExpression is not StructuralTypeShaperExpression { StructuralType : IEntityType entityType } shaper )
863871 {
864872 return null ;
865873 }
866874
867- if ( entityShaperExpression . StructuralType is not IEntityType entityType )
868- {
869- throw new UnreachableException ( "Complex types not supported in Cosmos" ) ;
870- }
871-
872875 if ( entityType . ClrType == resultType )
873876 {
874877 return source ;
875878 }
876879
877880 var select = ( SelectExpression ) source . QueryExpression ;
878881
879- var parameterExpression = Expression . Parameter ( entityShaperExpression . Type ) ;
882+ var parameterExpression = Expression . Parameter ( shaper . Type ) ;
880883 var predicate = Expression . Lambda ( Expression . TypeIs ( parameterExpression , resultType ) , parameterExpression ) ;
881884
882885 if ( ! TryApplyPredicate ( source , predicate ) )
@@ -887,23 +890,23 @@ protected override ShapedQueryExpression TranslateCast(ShapedQueryExpression sou
887890 var baseType = entityType . GetAllBaseTypes ( ) . SingleOrDefault ( et => et . ClrType == resultType ) ;
888891 if ( baseType != null )
889892 {
890- return source . UpdateShaperExpression ( entityShaperExpression . WithType ( baseType ) ) ;
893+ return source . UpdateShaperExpression ( shaper . WithType ( baseType ) ) ;
891894 }
892895
893896 var derivedType = entityType . GetDerivedTypes ( ) . Single ( et => et . ClrType == resultType ) ;
894- var projectionBindingExpression = ( ProjectionBindingExpression ) entityShaperExpression . ValueBufferExpression ;
897+ var projectionBindingExpression = ( ProjectionBindingExpression ) shaper . ValueBufferExpression ;
895898
896899 var projectionMember = projectionBindingExpression . ProjectionMember ;
897900 Check . DebugAssert ( new ProjectionMember ( ) . Equals ( projectionMember ) , "Invalid ProjectionMember when processing OfType" ) ;
898901
899- var entityProjectionExpression = ( EntityProjectionExpression ) select . GetMappedProjection ( projectionMember ) ;
902+ var structuralTypeProjectionExpression = ( StructuralTypeProjectionExpression ) select . GetMappedProjection ( projectionMember ) ;
900903 select . ReplaceProjectionMapping (
901904 new Dictionary < ProjectionMember , Expression >
902905 {
903- { projectionMember , entityProjectionExpression . UpdateEntityType ( derivedType ) }
906+ { projectionMember , structuralTypeProjectionExpression . UpdateEntityType ( derivedType ) }
904907 } ) ;
905908
906- return source . UpdateShaperExpression ( entityShaperExpression . WithType ( derivedType ) ) ;
909+ return source . UpdateShaperExpression ( shaper . WithType ( derivedType ) ) ;
907910 }
908911
909912 /// <summary>
@@ -1131,9 +1134,9 @@ protected override ShapedQueryExpression TranslateSelect(ShapedQueryExpression s
11311134 var translatedSelect = SelectExpression . CreateForCollection (
11321135 slice ,
11331136 alias ,
1134- new EntityProjectionExpression (
1135- new ObjectReferenceExpression ( ( IEntityType ) projectedStructuralTypeShaper . StructuralType , alias ) ,
1136- ( IEntityType ) projectedStructuralTypeShaper . StructuralType ) ) ;
1137+ new StructuralTypeProjectionExpression (
1138+ new ObjectReferenceExpression ( projectedStructuralTypeShaper . StructuralType , alias ) ,
1139+ projectedStructuralTypeShaper . StructuralType ) ) ;
11371140 return source . Update (
11381141 translatedSelect ,
11391142 new StructuralTypeShaperExpression (
@@ -1270,9 +1273,9 @@ protected override ShapedQueryExpression TranslateSelect(ShapedQueryExpression s
12701273 var translatedSelect = SelectExpression . CreateForCollection (
12711274 slice ,
12721275 alias ,
1273- new EntityProjectionExpression (
1274- new ObjectReferenceExpression ( ( IEntityType ) projectedStructuralTypeShaper . StructuralType , alias ) ,
1275- ( IEntityType ) projectedStructuralTypeShaper . StructuralType ) ) ;
1276+ new StructuralTypeProjectionExpression (
1277+ new ObjectReferenceExpression ( projectedStructuralTypeShaper . StructuralType , alias ) ,
1278+ projectedStructuralTypeShaper . StructuralType ) ) ;
12761279 return source . Update (
12771280 translatedSelect ,
12781281 new StructuralTypeShaperExpression (
@@ -1361,7 +1364,7 @@ protected override ShapedQueryExpression TranslateSelect(ShapedQueryExpression s
13611364 /// </summary>
13621365 protected override ShapedQueryExpression ? TranslateMemberAccess ( Expression source , MemberIdentity member )
13631366 {
1364- // Attempt to translate access into a primitive collection property
1367+ // Attempt to translate access into a primitive, complex or embedded owned navigation collection property
13651368 if ( _sqlTranslator . TryBindMember (
13661369 _sqlTranslator . Visit ( source ) ,
13671370 member ,
@@ -1378,20 +1381,19 @@ protected override ShapedQueryExpression TranslateSelect(ShapedQueryExpression s
13781381
13791382 switch ( translatedExpression )
13801383 {
1381- case StructuralTypeShaperExpression shaper when property is INavigation { IsCollection : true } :
1384+ case StructuralTypeShaperExpression shaper when property is INavigation { IsCollection : true }
1385+ or IComplexProperty { IsCollection : true } :
13821386 {
1383- var targetEntityType = ( IEntityType ) shaper . StructuralType ;
1384- var projection = new EntityProjectionExpression (
1385- new ObjectReferenceExpression ( targetEntityType , sourceAlias ) , targetEntityType ) ;
1387+ var targetStructuralType = shaper . StructuralType ;
1388+ var projection = new StructuralTypeProjectionExpression (
1389+ new ObjectReferenceExpression ( targetStructuralType , sourceAlias ) , targetStructuralType ) ;
13861390 var select = SelectExpression . CreateForCollection (
13871391 shaper . ValueBufferExpression ,
13881392 sourceAlias ,
13891393 projection ) ;
1390- return CreateShapedQueryExpression ( targetEntityType , select ) ;
1394+ return CreateShapedQueryExpression ( targetStructuralType , select ) ;
13911395 }
13921396
1393- // TODO: Collection of complex type (#31253)
1394-
13951397 // Note that non-collection navigations/complex types are handled in CosmosSqlTranslatingExpressionVisitor
13961398 // (no collection -> no queryable operators)
13971399
@@ -1666,7 +1668,7 @@ private bool TryPushdownIntoSubquery(SelectExpression select)
16661668 var translation = new ObjectFunctionExpression ( functionName , [ array1 , array2 ] , arrayType ) ;
16671669 var alias = _aliasManager . GenerateSourceAlias ( translation ) ;
16681670 var select = SelectExpression . CreateForCollection (
1669- translation , alias , new ObjectReferenceExpression ( ( IEntityType ) structuralType1 , alias ) ) ;
1671+ translation , alias , new ObjectReferenceExpression ( structuralType1 , alias ) ) ;
16701672 return CreateShapedQueryExpression ( select , structuralType1 . ClrType ) ;
16711673 }
16721674 }
0 commit comments