diff --git a/src/EFCore.Relational/Query/Pipeline/CollectionInitializingExperssion.cs b/src/EFCore.Relational/Query/Pipeline/CollectionInitializingExperssion.cs new file mode 100644 index 00000000000..950264789c9 --- /dev/null +++ b/src/EFCore.Relational/Query/Pipeline/CollectionInitializingExperssion.cs @@ -0,0 +1,65 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Query.Expressions.Internal; +using Microsoft.EntityFrameworkCore.Query.Internal; + +namespace Microsoft.EntityFrameworkCore.Relational.Query.Pipeline +{ + public class CollectionInitializingExpression : Expression, IPrintable + { + public CollectionInitializingExpression( + int collectionId, Expression parent, Expression parentIdentifier, Expression outerIdentifier, INavigation navigation, Type type) + { + CollectionId = collectionId; + Parent = parent; + ParentIdentifier = parentIdentifier; + OuterIdentifier = outerIdentifier; + Navigation = navigation; + Type = type; + } + + protected override Expression VisitChildren(ExpressionVisitor visitor) + { + var parent = visitor.Visit(Parent); + var parentIdentifier = visitor.Visit(ParentIdentifier); + var outerIdentifier = visitor.Visit(OuterIdentifier); + + return parent != Parent || parentIdentifier != ParentIdentifier || outerIdentifier != OuterIdentifier + ? new CollectionInitializingExpression(CollectionId, parent, parentIdentifier, outerIdentifier, Navigation, Type) + : this; + } + + public void Print(ExpressionPrinter expressionPrinter) + { + expressionPrinter.StringBuilder.AppendLine("InitializeCollection:"); + using (expressionPrinter.StringBuilder.Indent()) + { + expressionPrinter.StringBuilder.AppendLine($"CollectionId: {CollectionId}"); + expressionPrinter.StringBuilder.AppendLine($"Navigation: {Navigation?.Name}"); + expressionPrinter.StringBuilder.Append("Parent:"); + expressionPrinter.Visit(Parent); + expressionPrinter.StringBuilder.AppendLine(); + expressionPrinter.StringBuilder.Append("ParentIdentifier:"); + expressionPrinter.Visit(ParentIdentifier); + expressionPrinter.StringBuilder.AppendLine(); + expressionPrinter.StringBuilder.Append("OuterIdentifier:"); + expressionPrinter.Visit(OuterIdentifier); + expressionPrinter.StringBuilder.AppendLine(); + } + } + + public override Type Type { get; } + + public override ExpressionType NodeType => ExpressionType.Extension; + + public int CollectionId { get; } + public Expression Parent { get; } + public Expression ParentIdentifier { get; } + public Expression OuterIdentifier { get; } + public INavigation Navigation { get; } + } +} diff --git a/src/EFCore.Relational/Query/Pipeline/CollectionPopulatingExpression.cs b/src/EFCore.Relational/Query/Pipeline/CollectionPopulatingExpression.cs new file mode 100644 index 00000000000..c7d41bd99df --- /dev/null +++ b/src/EFCore.Relational/Query/Pipeline/CollectionPopulatingExpression.cs @@ -0,0 +1,45 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Query.Expressions.Internal; +using Microsoft.EntityFrameworkCore.Query.Internal; + +namespace Microsoft.EntityFrameworkCore.Relational.Query.Pipeline +{ + public class CollectionPopulatingExpression : Expression, IPrintable + { + public CollectionPopulatingExpression(RelationalCollectionShaperExpression parent, Type type, bool include) + { + Parent = parent; + Type = type; + Include = include; + } + + protected override Expression VisitChildren(ExpressionVisitor visitor) + { + var parent = (RelationalCollectionShaperExpression)visitor.Visit(Parent); + + return parent != Parent + ? new CollectionPopulatingExpression(parent, Type, Include) + : this; + } + + public void Print(ExpressionPrinter expressionPrinter) + { + expressionPrinter.StringBuilder.AppendLine("PopulateCollection:"); + using (expressionPrinter.StringBuilder.Indent()) + { + expressionPrinter.StringBuilder.Append("Parent:"); + expressionPrinter.Visit(Parent); + } + } + + public override Type Type { get; } + + public override ExpressionType NodeType => ExpressionType.Extension; + public RelationalCollectionShaperExpression Parent { get; } + public bool Include { get; } + } +} diff --git a/src/EFCore.Relational/Query/Pipeline/IncludeCompilingExpressionVisitor.cs b/src/EFCore.Relational/Query/Pipeline/IncludeCompilingExpressionVisitor.cs index d7c3a03bcd4..ac60499e67e 100644 --- a/src/EFCore.Relational/Query/Pipeline/IncludeCompilingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Pipeline/IncludeCompilingExpressionVisitor.cs @@ -81,30 +81,25 @@ private static readonly MethodInfo _populateCollectionMethodInfo = typeof(CustomShaperCompilingExpressionVisitor).GetTypeInfo() .GetDeclaredMethod(nameof(PopulateCollection)); - private static void PopulateCollection( + private static void PopulateCollection( int collectionId, QueryContext queryContext, DbDataReader dbDataReader, + ResultCoordinator resultCoordinator, Func parentIdentifier, Func outerIdentifier, Func selfIdentifier, - Func innerShaper, - INavigation inverseNavigation, - Action fixup, - bool trackingQuery, - ResultCoordinator resultCoordinator) + Func innerShaper) + where TCollection : class, ICollection { var collectionMaterializationContext = resultCoordinator.Collections[collectionId]; - var parent = collectionMaterializationContext.Parent; if (collectionMaterializationContext.Collection is null) { - // Nothing to include since parent was not materialized + // nothing to include since no collection created return; } - var entity = (TIncludingEntity)parent; - if (!StructuralComparisons.StructuralEqualityComparer.Equals( outerIdentifier(queryContext, dbDataReader), collectionMaterializationContext.OuterIdentifier)) { @@ -122,6 +117,12 @@ private static void PopulateCollection( } var innerKey = selfIdentifier(queryContext, dbDataReader); + if (innerKey.Any(e => e == null)) + { + // If innerKey was null then return since no related data + return; + } + if (StructuralComparisons.StructuralEqualityComparer.Equals( innerKey, collectionMaterializationContext.SelfIdentifier)) { @@ -133,44 +134,102 @@ private static void PopulateCollection( var relatedEntity = innerShaper(queryContext, dbDataReader, default, resultCoordinator); collectionMaterializationContext.UpdateCurrent(relatedEntity, innerKey); - if (relatedEntity is null) - { - return; - } - if (!trackingQuery) + ((TCollection)collectionMaterializationContext.Collection).Add(relatedEntity); + + resultCoordinator.ResultReady = false; + } + + private static readonly MethodInfo _populateIncludeCollectionMethodInfo + = typeof(CustomShaperCompilingExpressionVisitor).GetTypeInfo() + .GetDeclaredMethod(nameof(PopulateIncludeCollection)); + + private static void PopulateIncludeCollection( + int collectionId, + QueryContext queryContext, + DbDataReader dbDataReader, + ResultCoordinator resultCoordinator, + Func parentIdentifier, + Func outerIdentifier, + Func selfIdentifier, + Func innerShaper, + INavigation inverseNavigation, + Action fixup, + bool trackingQuery) + { + var collectionMaterializationContext = resultCoordinator.Collections[collectionId]; + var parentEntity = collectionMaterializationContext.Parent; + + if (parentEntity is TIncludingEntity entity) { - fixup(entity, relatedEntity); - if (inverseNavigation != null && !inverseNavigation.IsCollection()) + if (!StructuralComparisons.StructuralEqualityComparer.Equals( + outerIdentifier(queryContext, dbDataReader), collectionMaterializationContext.OuterIdentifier)) + { + if (StructuralComparisons.StructuralEqualityComparer.Equals( + parentIdentifier(queryContext, dbDataReader), collectionMaterializationContext.ParentIdentifier)) + { + resultCoordinator.ResultReady = false; + } + else + { + resultCoordinator.HasNext = true; + } + + return; + } + + var innerKey = selfIdentifier(queryContext, dbDataReader); + if (innerKey.Any(e => e == null)) { - SetIsLoadedNoTracking(relatedEntity, inverseNavigation); + // No correlated element + return; } - } - resultCoordinator.ResultReady = false; + if (StructuralComparisons.StructuralEqualityComparer.Equals( + innerKey, collectionMaterializationContext.SelfIdentifier)) + { + // We don't need to materialize this entity but we may need to populate inner collections if any. + innerShaper(queryContext, dbDataReader, (TIncludedEntity)collectionMaterializationContext.Current, resultCoordinator); + + return; + } + + var relatedEntity = innerShaper(queryContext, dbDataReader, default, resultCoordinator); + collectionMaterializationContext.UpdateCurrent(relatedEntity, innerKey); + + if (!trackingQuery) + { + fixup(entity, relatedEntity); + if (inverseNavigation != null && !inverseNavigation.IsCollection()) + { + SetIsLoadedNoTracking(relatedEntity, inverseNavigation); + } + } + + resultCoordinator.ResultReady = false; + } } - private static readonly MethodInfo _initializeCollectionIncludeMethodInfo + private static readonly MethodInfo _initializeIncludeCollectionMethodInfo = typeof(CustomShaperCompilingExpressionVisitor).GetTypeInfo() - .GetDeclaredMethod(nameof(InitializeCollectionInclude)); + .GetDeclaredMethod(nameof(InitializeIncludeCollection)); - private static void InitializeCollectionInclude( + private static void InitializeIncludeCollection( int collectionId, QueryContext queryContext, DbDataReader dbDataReader, ResultCoordinator resultCoordinator, - TEntity entity, + TParent entity, Func parentIdenfier, Func outerIdentifier, INavigation navigation, IClrCollectionAccessor clrCollectionAccessor, bool trackingQuery) - where TIncludingEntity : TEntity + where TNavigationEntity : TParent { object collection = null; - if (entity is TIncludingEntity) + if (entity is TNavigationEntity) { - // Include case if (trackingQuery) { queryContext.StateManager.TryGetEntry(entity).SetIsLoaded(navigation); @@ -191,6 +250,32 @@ private static void InitializeCollectionInclude( resultCoordinator.SetCollectionMaterializationContext(collectionId, collectionMaterializationContext); } + private static readonly MethodInfo _initializeCollectionMethodInfo + = typeof(CustomShaperCompilingExpressionVisitor).GetTypeInfo() + .GetDeclaredMethod(nameof(InitializeCollection)); + + private static TCollection InitializeCollection( + int collectionId, + QueryContext queryContext, + DbDataReader dbDataReader, + ResultCoordinator resultCoordinator, + Func parentIdenfier, + Func outerIdentifier, + IClrCollectionAccessor clrCollectionAccessor) + where TCollection :class, IEnumerable + { + var collection = clrCollectionAccessor?.Create() ?? new List(); + + var parentKey = parentIdenfier(queryContext, dbDataReader); + var outerKey = outerIdentifier(queryContext, dbDataReader); + + var collectionMaterializationContext = new CollectionMaterializationContext(null, collection, parentKey, outerKey); + + resultCoordinator.SetCollectionMaterializationContext(collectionId, collectionMaterializationContext); + + return (TCollection)collection; + } + private static void SetIsLoadedNoTracking(object entity, INavigation navigation) => ((ILazyLoader)((PropertyBase)navigation .DeclaringEntityType @@ -209,7 +294,8 @@ protected override Expression VisitExtension(Expression extensionExpression) var includingClrType = includeExpression.Navigation.DeclaringEntityType.ClrType; var inverseNavigation = includeExpression.Navigation.FindInverse(); var relatedEntityClrType = includeExpression.Navigation.GetTargetType().ClrType; - if (includingClrType.IsAssignableFrom(entityClrType)) + if (includingClrType != entityClrType + && includingClrType.IsAssignableFrom(entityClrType)) { includingClrType = entityClrType; } @@ -227,51 +313,110 @@ protected override Expression VisitExtension(Expression extensionExpression) Expression.Constant(_tracking)); } - if (extensionExpression is CollectionInitializingExperssion collectionInitializingExperssion) + if (extensionExpression is CollectionInitializingExpression collectionInitializingExpression) { - var entityClrType = collectionInitializingExperssion.Parent.Type; - var includingClrType = collectionInitializingExperssion.Navigation.DeclaringEntityType.ClrType; - if (includingClrType.IsAssignableFrom(entityClrType)) + if (collectionInitializingExpression.Parent != null) { - includingClrType = entityClrType; + // Include case + var entityClrType = collectionInitializingExpression.Parent.Type; + var includingClrType = collectionInitializingExpression.Navigation.DeclaringEntityType.ClrType; + if (includingClrType != entityClrType + && includingClrType.IsAssignableFrom(entityClrType)) + { + includingClrType = entityClrType; + } + + return Expression.Call( + _initializeIncludeCollectionMethodInfo.MakeGenericMethod(entityClrType, includingClrType), + Expression.Constant(collectionInitializingExpression.CollectionId), + QueryCompilationContext.QueryContextParameter, + _dbDataReaderParameter, + _resultCoordinatorParameter, + collectionInitializingExpression.Parent, + Expression.Constant( + Expression.Lambda( + collectionInitializingExpression.ParentIdentifier, + QueryCompilationContext.QueryContextParameter, + _dbDataReaderParameter).Compile()), + Expression.Constant( + Expression.Lambda( + collectionInitializingExpression.OuterIdentifier, + QueryCompilationContext.QueryContextParameter, + _dbDataReaderParameter).Compile()), + Expression.Constant(collectionInitializingExpression.Navigation), + Expression.Constant(collectionInitializingExpression.Navigation.GetCollectionAccessor()), + Expression.Constant(_tracking)); } + var collectionClrType = collectionInitializingExpression.Type; + var elementType = collectionClrType.TryGetSequenceType(); + return Expression.Call( - _initializeCollectionIncludeMethodInfo.MakeGenericMethod(entityClrType, includingClrType), - Expression.Constant(collectionInitializingExperssion.CollectionId), + _initializeCollectionMethodInfo.MakeGenericMethod(elementType, collectionClrType), + Expression.Constant(collectionInitializingExpression.CollectionId), QueryCompilationContext.QueryContextParameter, _dbDataReaderParameter, _resultCoordinatorParameter, - collectionInitializingExperssion.Parent, Expression.Constant( Expression.Lambda( - collectionInitializingExperssion.ParentIdentifier, + collectionInitializingExpression.ParentIdentifier, QueryCompilationContext.QueryContextParameter, _dbDataReaderParameter).Compile()), Expression.Constant( Expression.Lambda( - collectionInitializingExperssion.OuterIdentifier, + collectionInitializingExpression.OuterIdentifier, QueryCompilationContext.QueryContextParameter, _dbDataReaderParameter).Compile()), - Expression.Constant(collectionInitializingExperssion.Navigation), - Expression.Constant(collectionInitializingExperssion.Navigation.GetCollectionAccessor()), - Expression.Constant(_tracking)); + Expression.Constant(collectionInitializingExpression.Navigation?.GetCollectionAccessor(), + typeof(IClrCollectionAccessor))); } if (extensionExpression is CollectionPopulatingExpression collectionPopulatingExpression) { var collectionShaper = collectionPopulatingExpression.Parent; - var entityClrType = collectionShaper.Navigation.DeclaringEntityType.ClrType; - var relatedEntityClrType = collectionShaper.Navigation.GetTargetType().ClrType; - var inverseNavigation = collectionShaper.Navigation.FindInverse(); - var innerShaper = Visit(collectionShaper.InnerShaper); - innerShaper = Expression.Constant(((LambdaExpression)innerShaper).Compile()); + var relatedEntityClrType = ((LambdaExpression)collectionShaper.InnerShaper).ReturnType; + + if (collectionPopulatingExpression.Include) + { + var entityClrType = collectionShaper.Navigation.DeclaringEntityType.ClrType; + var inverseNavigation = collectionShaper.Navigation.FindInverse(); + + return Expression.Call( + _populateIncludeCollectionMethodInfo.MakeGenericMethod(entityClrType, relatedEntityClrType), + Expression.Constant(collectionShaper.CollectionId), + QueryCompilationContext.QueryContextParameter, + _dbDataReaderParameter, + _resultCoordinatorParameter, + Expression.Constant( + Expression.Lambda( + collectionShaper.ParentIdentifier, + QueryCompilationContext.QueryContextParameter, + _dbDataReaderParameter).Compile()), + Expression.Constant( + Expression.Lambda( + collectionShaper.OuterIdentifier, + QueryCompilationContext.QueryContextParameter, + _dbDataReaderParameter).Compile()), + Expression.Constant( + Expression.Lambda( + collectionShaper.SelfIdentifier, + QueryCompilationContext.QueryContextParameter, + _dbDataReaderParameter).Compile()), + Expression.Constant(((LambdaExpression)Visit(collectionShaper.InnerShaper)).Compile()), + Expression.Constant(inverseNavigation, typeof(INavigation)), + Expression.Constant( + GenerateFixup(entityClrType, relatedEntityClrType, collectionShaper.Navigation, inverseNavigation).Compile()), + Expression.Constant(_tracking)); + } + + var collectionType = collectionPopulatingExpression.Type; return Expression.Call( - _populateCollectionMethodInfo.MakeGenericMethod(entityClrType, relatedEntityClrType), + _populateCollectionMethodInfo.MakeGenericMethod(collectionType, relatedEntityClrType), Expression.Constant(collectionShaper.CollectionId), QueryCompilationContext.QueryContextParameter, _dbDataReaderParameter, + _resultCoordinatorParameter, Expression.Constant( Expression.Lambda( collectionShaper.ParentIdentifier, @@ -287,12 +432,7 @@ protected override Expression VisitExtension(Expression extensionExpression) collectionShaper.SelfIdentifier, QueryCompilationContext.QueryContextParameter, _dbDataReaderParameter).Compile()), - innerShaper, - Expression.Constant(inverseNavigation, typeof(INavigation)), - Expression.Constant( - GenerateFixup(entityClrType, relatedEntityClrType, collectionShaper.Navigation, inverseNavigation).Compile()), - Expression.Constant(_tracking), - _resultCoordinatorParameter); + Expression.Constant(((LambdaExpression)Visit(collectionShaper.InnerShaper)).Compile())); } return base.VisitExtension(extensionExpression); diff --git a/src/EFCore.Relational/Query/Pipeline/RelationalCollectionShaperExpression.cs b/src/EFCore.Relational/Query/Pipeline/RelationalCollectionShaperExpression.cs index 87611cf1f87..3005cad8992 100644 --- a/src/EFCore.Relational/Query/Pipeline/RelationalCollectionShaperExpression.cs +++ b/src/EFCore.Relational/Query/Pipeline/RelationalCollectionShaperExpression.cs @@ -7,7 +7,6 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Query.Expressions.Internal; using Microsoft.EntityFrameworkCore.Query.Internal; -using Microsoft.EntityFrameworkCore.Query.Pipeline; namespace Microsoft.EntityFrameworkCore.Relational.Query.Pipeline { @@ -36,7 +35,7 @@ public RelationalCollectionShaperExpression( public Expression InnerShaper { get; } public INavigation Navigation { get; } - public override Type Type => typeof(IEnumerable<>).MakeGenericType(InnerShaper.Type); + public override Type Type => Navigation?.ClrType ?? typeof(List<>).MakeGenericType(InnerShaper.Type); public override ExpressionType NodeType => ExpressionType.Extension; protected override Expression VisitChildren(ExpressionVisitor visitor) @@ -79,7 +78,7 @@ public void Print(ExpressionPrinter expressionPrinter) expressionPrinter.StringBuilder.Append("InnerShaper:"); expressionPrinter.Visit(InnerShaper); expressionPrinter.StringBuilder.AppendLine(); - expressionPrinter.StringBuilder.AppendLine($"Navigation: {Navigation.Name}"); + expressionPrinter.StringBuilder.AppendLine($"Navigation: {Navigation?.Name}"); } } diff --git a/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingExpressionVisitor.cs b/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingExpressionVisitor.cs index 8dcc576d2dc..1f55a1a944e 100644 --- a/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingExpressionVisitor.cs @@ -94,13 +94,32 @@ public override Expression Visit(Expression expression) Expression.Constant(parameterExpression.Name)); } - if (expression is MethodCallExpression methodCallExpression - && methodCallExpression.Method.Name == "MaterializeCollectionNavigation") + if (expression is MethodCallExpression methodCallExpression) { - var result = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression.Arguments[0]); - var navigation = (INavigation)((ConstantExpression)methodCallExpression.Arguments[1]).Value; - - return _selectExpression.AddCollectionProjection(result, navigation); + if (methodCallExpression.Method.Name == "MaterializeCollectionNavigation") + { + var result = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression.Arguments[0]); + var navigation = (INavigation)((ConstantExpression)methodCallExpression.Arguments[1]).Value; + + return _selectExpression.AddCollectionProjection(result, navigation); + } + + if (methodCallExpression.Method.Name == "ToList") + { + var result = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression.Arguments[0]); + + return _selectExpression.AddCollectionProjection(result, null); + } + + var subquery = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression); + + if (subquery != null) + { + if (subquery.ResultType == ResultType.Enumerable) + { + return _selectExpression.AddCollectionProjection(subquery, null); + } + } } var translation = _sqlTranslator.Translate(expression); diff --git a/src/EFCore.Relational/Query/Pipeline/RelationalSqlTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/Pipeline/RelationalSqlTranslatingExpressionVisitor.cs index 20d5bc10fdf..05ca4f2c73e 100644 --- a/src/EFCore.Relational/Query/Pipeline/RelationalSqlTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Pipeline/RelationalSqlTranslatingExpressionVisitor.cs @@ -176,24 +176,28 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp return BindProperty(source, propertyName); } - if (methodCallExpression.Method.DeclaringType == typeof(Queryable)) + var subqueryTranslation = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression); + if (subqueryTranslation != null) { - var translation = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression); + if (subqueryTranslation.ResultType == ResultType.Enumerable) + { + return null; + } - var subquery = (SelectExpression)translation.QueryExpression; + var subquery = (SelectExpression)subqueryTranslation.QueryExpression; subquery.ApplyProjection(); - if (methodCallExpression.Method.Name == nameof(Queryable.Any) + if (subquery.Projection.Count != 1) + { + return null; + } + + if ((methodCallExpression.Method.Name == nameof(Queryable.Any) || methodCallExpression.Method.Name == nameof(Queryable.All) || methodCallExpression.Method.Name == nameof(Queryable.Contains)) + && subquery.Tables.Count == 0) { - if (subquery.Tables.Count == 0 - && subquery.Projection.Count == 1) - { - return subquery.Projection[0].Expression; - } - - throw new InvalidOperationException(); + return subquery.Projection[0].Expression; } return new SubSelectExpression(subquery); diff --git a/src/EFCore.Relational/Query/Pipeline/ShaperExpressionDedupingExpressionVisitor.cs b/src/EFCore.Relational/Query/Pipeline/ShaperExpressionDedupingExpressionVisitor.cs index 9615c8ed74f..147e05bcaf0 100644 --- a/src/EFCore.Relational/Query/Pipeline/ShaperExpressionDedupingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Pipeline/ShaperExpressionDedupingExpressionVisitor.cs @@ -1,14 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Linq.Expressions; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Query.Expressions.Internal; -using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Query.NavigationExpansion; using Microsoft.EntityFrameworkCore.Query.Pipeline; using Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.SqlExpressions; @@ -94,66 +90,96 @@ private LambdaExpression ConvertToLambda(Expression result, ParameterExpression protected override Expression VisitExtension(Expression extensionExpression) { - if (extensionExpression is EntityShaperExpression entityShaperExpression) + switch (extensionExpression) { - var key = GenerateKey((ProjectionBindingExpression)entityShaperExpression.ValueBufferExpression); - if (!_mapping.TryGetValue(key, out var variable)) - { - variable = Expression.Parameter(entityShaperExpression.EntityType.ClrType); - _variables.Add(variable); - _expressions.Add(Expression.Assign(variable, entityShaperExpression)); - _mapping[key] = variable; - } - - return variable; - } - - if (extensionExpression is ProjectionBindingExpression projectionBindingExpression) - { - var key = GenerateKey(projectionBindingExpression); - if (!_mapping.TryGetValue(key, out var variable)) - { - variable = Expression.Parameter(projectionBindingExpression.Type); - _variables.Add(variable); - _expressions.Add(Expression.Assign(variable, projectionBindingExpression)); - _mapping[key] = variable; - } - - return variable; - } - - if (extensionExpression is IncludeExpression includeExpression) - { - var entity = Visit(includeExpression.EntityExpression); - if (includeExpression.NavigationExpression is RelationalCollectionShaperExpression relationalCollectionShaperExpression) - { - var innerShaper = new ShaperExpressionProcessingExpressionVisitor( - _selectExpression, _dataReaderParameter, _resultCoordinatorParameter, null) - .Inject(relationalCollectionShaperExpression.InnerShaper); - - _expressions.Add(new CollectionInitializingExperssion( - relationalCollectionShaperExpression.CollectionId, - entity, - relationalCollectionShaperExpression.ParentIdentifier, - relationalCollectionShaperExpression.OuterIdentifier, - includeExpression.Navigation)); - - _collectionPopulatingExpressions.Add(new CollectionPopulatingExpression( - relationalCollectionShaperExpression.Update( + case EntityShaperExpression entityShaperExpression: + { + var key = GenerateKey((ProjectionBindingExpression)entityShaperExpression.ValueBufferExpression); + if (!_mapping.TryGetValue(key, out var variable)) + { + variable = Expression.Parameter(entityShaperExpression.EntityType.ClrType); + _variables.Add(variable); + _expressions.Add(Expression.Assign(variable, entityShaperExpression)); + _mapping[key] = variable; + } + + return variable; + } + + case ProjectionBindingExpression projectionBindingExpression: + { + var key = GenerateKey(projectionBindingExpression); + if (!_mapping.TryGetValue(key, out var variable)) + { + variable = Expression.Parameter(projectionBindingExpression.Type); + _variables.Add(variable); + _expressions.Add(Expression.Assign(variable, projectionBindingExpression)); + _mapping[key] = variable; + } + + return variable; + } + + case IncludeExpression includeExpression: + { + var entity = Visit(includeExpression.EntityExpression); + if (includeExpression.NavigationExpression is RelationalCollectionShaperExpression + relationalCollectionShaperExpression) + { + var innerShaper = new ShaperExpressionProcessingExpressionVisitor( + _selectExpression, _dataReaderParameter, _resultCoordinatorParameter, null) + .Inject(relationalCollectionShaperExpression.InnerShaper); + + _collectionPopulatingExpressions.Add(new CollectionPopulatingExpression( + relationalCollectionShaperExpression.Update( + relationalCollectionShaperExpression.ParentIdentifier, + relationalCollectionShaperExpression.OuterIdentifier, + relationalCollectionShaperExpression.SelfIdentifier, + innerShaper), + includeExpression.Navigation.ClrType, + true)); + + _expressions.Add(new CollectionInitializingExpression( + relationalCollectionShaperExpression.CollectionId, + entity, relationalCollectionShaperExpression.ParentIdentifier, relationalCollectionShaperExpression.OuterIdentifier, - relationalCollectionShaperExpression.SelfIdentifier, - innerShaper), - true)); - } - else - { - _expressions.Add(includeExpression.Update( - entity, - Visit(includeExpression.NavigationExpression))); - } - - return entity; + includeExpression.Navigation, + includeExpression.Navigation.ClrType)); + } + else + { + _expressions.Add(includeExpression.Update( + entity, + Visit(includeExpression.NavigationExpression))); + } + + return entity; + } + + case RelationalCollectionShaperExpression relationalCollectionShaperExpression2: + { + var innerShaper = new ShaperExpressionProcessingExpressionVisitor( + _selectExpression, _dataReaderParameter, _resultCoordinatorParameter, null) + .Inject(relationalCollectionShaperExpression2.InnerShaper); + + _collectionPopulatingExpressions.Add(new CollectionPopulatingExpression( + relationalCollectionShaperExpression2.Update( + relationalCollectionShaperExpression2.ParentIdentifier, + relationalCollectionShaperExpression2.OuterIdentifier, + relationalCollectionShaperExpression2.SelfIdentifier, + innerShaper), + relationalCollectionShaperExpression2.Type, + false)); + + return new CollectionInitializingExpression( + relationalCollectionShaperExpression2.CollectionId, + null, + relationalCollectionShaperExpression2.ParentIdentifier, + relationalCollectionShaperExpression2.OuterIdentifier, + relationalCollectionShaperExpression2.Navigation, + relationalCollectionShaperExpression2.Type); + } } return base.VisitExtension(extensionExpression); @@ -166,91 +192,4 @@ private Expression GenerateKey(ProjectionBindingExpression projectionBindingExpr : projectionBindingExpression; } } - - public class CollectionInitializingExperssion : Expression, IPrintable - { - public CollectionInitializingExperssion( - int collectionId, Expression parent, Expression parentIdentifier, Expression outerIdentifier, INavigation navigation) - { - CollectionId = collectionId; - Parent = parent; - ParentIdentifier = parentIdentifier; - OuterIdentifier = outerIdentifier; - Navigation = navigation; - } - - protected override Expression VisitChildren(ExpressionVisitor visitor) - { - var parent = visitor.Visit(Parent); - var parentIdentifier = visitor.Visit(ParentIdentifier); - var outerIdentifier = visitor.Visit(OuterIdentifier); - - return parent != Parent || parentIdentifier != ParentIdentifier || outerIdentifier != OuterIdentifier - ? new CollectionInitializingExperssion(CollectionId, parent, parentIdentifier, outerIdentifier, Navigation) - : this; - } - - public void Print(ExpressionPrinter expressionPrinter) - { - expressionPrinter.StringBuilder.AppendLine("InitializeCollection:"); - using (expressionPrinter.StringBuilder.Indent()) - { - expressionPrinter.StringBuilder.AppendLine($"CollectionId: {CollectionId}"); - expressionPrinter.StringBuilder.AppendLine($"Navigation: {Navigation.Name}"); - expressionPrinter.StringBuilder.Append("Parent:"); - expressionPrinter.Visit(Parent); - expressionPrinter.StringBuilder.AppendLine(); - expressionPrinter.StringBuilder.Append("ParentIdentifier:"); - expressionPrinter.Visit(ParentIdentifier); - expressionPrinter.StringBuilder.AppendLine(); - expressionPrinter.StringBuilder.Append("OuterIdentifier:"); - expressionPrinter.Visit(OuterIdentifier); - expressionPrinter.StringBuilder.AppendLine(); - } - } - - public override Type Type => Navigation.ClrType; - - public override ExpressionType NodeType => ExpressionType.Extension; - - public int CollectionId { get; } - public Expression Parent { get; } - public Expression ParentIdentifier { get; } - public Expression OuterIdentifier { get; } - public INavigation Navigation { get; } - } - - public class CollectionPopulatingExpression : Expression, IPrintable - { - public CollectionPopulatingExpression(RelationalCollectionShaperExpression parent, bool include) - { - Parent = parent; - Include = include; - } - - protected override Expression VisitChildren(ExpressionVisitor visitor) - { - var parent = (RelationalCollectionShaperExpression)visitor.Visit(Parent); - - return parent != Parent - ? new CollectionPopulatingExpression(parent, Include) - : this; - } - - public void Print(ExpressionPrinter expressionPrinter) - { - expressionPrinter.StringBuilder.AppendLine("PopulateCollection:"); - using (expressionPrinter.StringBuilder.Indent()) - { - expressionPrinter.StringBuilder.Append("Parent:"); - expressionPrinter.Visit(Parent); - } - } - - public override Type Type => typeof(void); - - public override ExpressionType NodeType => ExpressionType.Extension; - public RelationalCollectionShaperExpression Parent { get; } - public bool Include { get; } - } } diff --git a/src/EFCore.Relational/Query/Pipeline/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/Pipeline/SqlExpressions/SelectExpression.cs index a4ac793e565..758da346792 100644 --- a/src/EFCore.Relational/Query/Pipeline/SqlExpressions/SelectExpression.cs +++ b/src/EFCore.Relational/Query/Pipeline/SqlExpressions/SelectExpression.cs @@ -704,8 +704,7 @@ public Expression ApplyCollectionJoin(int collectionIndex, int collectionId, Exp selfIdentifier = shaperRemapper.Visit(selfIdentifier); return new RelationalCollectionShaperExpression( - collectionId, parentIdentifier, outerIdentifier, selfIdentifier, innerShaper, - navigation); + collectionId, parentIdentifier, outerIdentifier, selfIdentifier, innerShaper, navigation); } throw new NotImplementedException(); @@ -717,7 +716,7 @@ private Expression GetIdentifierAccessor(IEnumerable identifyingP foreach (var keyExpression in identifyingProjection) { var index = AddToProjection(keyExpression); - var projectionBindingExpression = new ProjectionBindingExpression(this, index, keyExpression.Type); + var projectionBindingExpression = new ProjectionBindingExpression(this, index, keyExpression.Type.MakeNullable()); updatedExpressions.Add( projectionBindingExpression.Type.IsValueType @@ -842,12 +841,14 @@ private SqlBinaryExpression ValidateKeyComparison(SelectExpression inner, SqlBin if (ContainsTableReference(leftColumn.Table) && inner.ContainsTableReference(rightColumn.Table)) { + inner.AddToProjection(rightColumn); return sqlBinaryExpression; } if (ContainsTableReference(rightColumn.Table) && inner.ContainsTableReference(leftColumn.Table)) { + inner.AddToProjection(leftColumn); return sqlBinaryExpression.Update( sqlBinaryExpression.Right, sqlBinaryExpression.Left); diff --git a/src/EFCore/Query/Pipeline/CollectionShaperExpression.cs b/src/EFCore/Query/Pipeline/CollectionShaperExpression.cs new file mode 100644 index 00000000000..84ed2c16abf --- /dev/null +++ b/src/EFCore/Query/Pipeline/CollectionShaperExpression.cs @@ -0,0 +1,60 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Query.Expressions.Internal; +using Microsoft.EntityFrameworkCore.Query.Internal; + +namespace Microsoft.EntityFrameworkCore.Query.Pipeline +{ + public class CollectionShaperExpression : Expression, IPrintable + { + public CollectionShaperExpression( + ProjectionBindingExpression projection, + Expression innerShaper, + INavigation navigation) + { + Projection = projection; + InnerShaper = innerShaper; + Navigation = navigation; + } + + protected override Expression VisitChildren(ExpressionVisitor visitor) + { + var projection = (ProjectionBindingExpression)visitor.Visit(Projection); + var innerShaper = visitor.Visit(InnerShaper); + + return Update(projection, innerShaper); + } + + public CollectionShaperExpression Update(ProjectionBindingExpression projection, Expression innerShaper) + { + return projection != Projection || innerShaper != InnerShaper + ? new CollectionShaperExpression(projection, innerShaper, Navigation) + : this; + } + + public override ExpressionType NodeType => ExpressionType.Extension; + + public override Type Type => Navigation?.ClrType ?? typeof(List<>).MakeGenericType(InnerShaper.Type); + + public ProjectionBindingExpression Projection { get; } + public Expression InnerShaper { get; } + public INavigation Navigation { get; } + + public virtual void Print(ExpressionPrinter expressionPrinter) + { + expressionPrinter.StringBuilder.AppendLine("CollectionShaper:"); + expressionPrinter.StringBuilder.IncrementIndent(); + expressionPrinter.StringBuilder.Append("("); + expressionPrinter.Visit(Projection); + expressionPrinter.StringBuilder.Append(", "); + expressionPrinter.Visit(InnerShaper); + expressionPrinter.StringBuilder.AppendLine($", {Navigation?.Name})"); + expressionPrinter.StringBuilder.DecrementIndent(); + } + } +} diff --git a/src/EFCore/Query/Pipeline/EntityShaperExpression.cs b/src/EFCore/Query/Pipeline/EntityShaperExpression.cs index 39bb8f6eae9..a30147c8392 100644 --- a/src/EFCore/Query/Pipeline/EntityShaperExpression.cs +++ b/src/EFCore/Query/Pipeline/EntityShaperExpression.cs @@ -114,81 +114,4 @@ public void Print(ExpressionPrinter expressionPrinter) } } } - - public class EntityValuesExpression : Expression - { - public EntityValuesExpression(IEntityType entityType, ProjectionBindingExpression valueBufferExpression) - { - EntityType = entityType; - ValueBufferExpression = valueBufferExpression; - } - - public IEntityType EntityType { get; } - public ProjectionBindingExpression ValueBufferExpression { get; } - - protected override Expression VisitChildren(ExpressionVisitor visitor) - { - var valueBufferExpression = (ProjectionBindingExpression)visitor.Visit(ValueBufferExpression); - - return Update(valueBufferExpression); - } - - public EntityValuesExpression Update(ProjectionBindingExpression valueBufferExpression) - { - return valueBufferExpression != ValueBufferExpression - ? new EntityValuesExpression(EntityType, valueBufferExpression) - : this; - } - - public override Type Type => typeof(object[]); - public override ExpressionType NodeType => ExpressionType.Extension; - } - - public class CollectionShaperExpression : Expression, IPrintable - { - public CollectionShaperExpression( - ProjectionBindingExpression projection, - Expression innerShaper, - INavigation navigation) - { - Projection = projection; - InnerShaper = innerShaper; - Navigation = navigation; - } - - protected override Expression VisitChildren(ExpressionVisitor visitor) - { - var projection = (ProjectionBindingExpression)visitor.Visit(Projection); - var innerShaper = visitor.Visit(InnerShaper); - - return Update(projection, innerShaper); - } - - public CollectionShaperExpression Update(ProjectionBindingExpression projection, Expression innerShaper) - { - return projection != Projection || innerShaper != InnerShaper - ? new CollectionShaperExpression(projection, innerShaper, Navigation) - : this; - } - - public override ExpressionType NodeType => ExpressionType.Extension; - - public override Type Type => typeof(IEnumerable<>).MakeGenericType(InnerShaper.Type); - - public ProjectionBindingExpression Projection { get; } - public Expression InnerShaper { get; } - public INavigation Navigation { get; } - - public virtual void Print(ExpressionPrinter expressionPrinter) - { - expressionPrinter.StringBuilder.AppendLine("CollectionShaper:"); - expressionPrinter.StringBuilder.IncrementIndent(); - expressionPrinter.StringBuilder.Append("("); - expressionPrinter.Visit(Projection); - expressionPrinter.StringBuilder.Append(", "); - expressionPrinter.Visit(InnerShaper); - expressionPrinter.StringBuilder.AppendLine($", {Navigation.Name})"); - expressionPrinter.StringBuilder.DecrementIndent(); - } - } } diff --git a/src/EFCore/Query/Pipeline/EntityValuesExpression.cs b/src/EFCore/Query/Pipeline/EntityValuesExpression.cs new file mode 100644 index 00000000000..5f6fcaccfcb --- /dev/null +++ b/src/EFCore/Query/Pipeline/EntityValuesExpression.cs @@ -0,0 +1,38 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Metadata; + +namespace Microsoft.EntityFrameworkCore.Query.Pipeline +{ + public class EntityValuesExpression : Expression + { + public EntityValuesExpression(IEntityType entityType, ProjectionBindingExpression valueBufferExpression) + { + EntityType = entityType; + ValueBufferExpression = valueBufferExpression; + } + + public IEntityType EntityType { get; } + public ProjectionBindingExpression ValueBufferExpression { get; } + + protected override Expression VisitChildren(ExpressionVisitor visitor) + { + var valueBufferExpression = (ProjectionBindingExpression)visitor.Visit(ValueBufferExpression); + + return Update(valueBufferExpression); + } + + public EntityValuesExpression Update(ProjectionBindingExpression valueBufferExpression) + { + return valueBufferExpression != ValueBufferExpression + ? new EntityValuesExpression(EntityType, valueBufferExpression) + : this; + } + + public override Type Type => typeof(object[]); + public override ExpressionType NodeType => ExpressionType.Extension; + } +} diff --git a/test/EFCore.Specification.Tests/Query/AsyncSimpleQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/AsyncSimpleQueryTestBase.cs index 30f7c041236..0136eaa959c 100644 --- a/test/EFCore.Specification.Tests/Query/AsyncSimpleQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/AsyncSimpleQueryTestBase.cs @@ -78,7 +78,7 @@ public virtual async Task ToList_context_subquery_deadlock_issue() } } - [ConditionalFact(Skip = "issue #15043")] + [ConditionalFact(Skip = "issue #16076")] public virtual async Task ToArray_on_nav_subquery_in_projection() { using (var context = CreateContext()) diff --git a/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs index 70a9eabbb93..ef8fb2c63c2 100644 --- a/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs @@ -2287,7 +2287,7 @@ where l2s.Any(l2 => l2.Level1_Required_Id == l1.Id) select l1.Name).Distinct()); } - [ConditionalTheory(Skip = "Issue #15043")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Correlated_subquery_doesnt_project_unnecessary_columns_in_top_level_join(bool isAsync) { @@ -4767,7 +4767,7 @@ orderby l3.Id } } - [ConditionalTheory(Skip = "issue #15043")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Project_collection_navigation(bool isAsync) { @@ -4788,7 +4788,7 @@ public virtual Task Project_collection_navigation(bool isAsync) }); } - [ConditionalTheory(Skip = "issue #15043")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Project_collection_navigation_nested(bool isAsync) { @@ -4811,7 +4811,7 @@ select Maybe(l1.OneToOne_Optional_FK1, () => l1.OneToOne_Optional_FK1.OneToMany_ }); } - [ConditionalTheory(Skip = "issue #15043")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Project_collection_navigation_using_ef_property(bool isAsync) { @@ -4838,7 +4838,7 @@ select Maybe(l1.OneToOne_Optional_FK1, () => l1.OneToOne_Optional_FK1.OneToMany_ }); } - [ConditionalTheory(Skip = "issue #15043")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Project_collection_navigation_nested_anonymous(bool isAsync) { @@ -4898,7 +4898,7 @@ public virtual Task Project_collection_navigation_count(bool isAsync) elementSorter: e => e.Id); } - [ConditionalTheory(Skip = "Issue #15043")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Project_collection_navigation_composed(bool isAsync) { @@ -4926,7 +4926,7 @@ where l1.Id < 3 }); } - [ConditionalTheory(Skip = "Issue #15043")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Project_collection_and_root_entity(bool isAsync) { @@ -4953,7 +4953,7 @@ public virtual Task Project_collection_and_root_entity(bool isAsync) }); } - [ConditionalTheory(Skip = "Issue #15043")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Project_collection_and_include(bool isAsync) { @@ -4980,7 +4980,7 @@ public virtual Task Project_collection_and_include(bool isAsync) }); } - [ConditionalTheory(Skip = "issue #15043")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Project_navigation_and_collection(bool isAsync) { @@ -5500,7 +5500,7 @@ public virtual Task Null_check_in_anonymous_type_projection_should_not_be_remove }); } - [ConditionalTheory(Skip = "issue #15043")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Null_check_in_Dto_projection_should_not_be_removed(bool isAsync) { @@ -6132,7 +6132,7 @@ public virtual Task Join_with_navigations_in_the_result_selector1(bool isAsync) (l1s, l2s) => l1s.Join(l2s, l1 => l1.Id, l2 => l2.Level1_Required_Id, (o, i) => new { o.OneToOne_Optional_FK1, i })); } - [ConditionalFact(Skip = "Issue #15043")] + [ConditionalFact] public virtual void Join_with_navigations_in_the_result_selector2() { using (var ctx = CreateContext()) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs index 848c8a4f2eb..b07336a603f 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs @@ -28,7 +28,7 @@ public AsyncSimpleQuerySqlServerTest( //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } - [ConditionalFact] + [ConditionalFact(Skip = "Issue#16311")] public Task Query_compiler_concurrency() { const int threadCount = 50; diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs index 27b38b23935..c127078608a 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs @@ -2428,7 +2428,6 @@ await base.Complex_SelectMany_with_nested_navigations_and_explicit_DefaultIfEmpt isAsync); // issue #15081 - // issue #15043 // AssertSql( // @"SELECT [l1.OneToOne_Required_FK1.OneToOne_Optional_FK2.OneToMany_Required3].[Id], [l1.OneToOne_Required_FK1.OneToOne_Optional_FK2.OneToMany_Required3].[Level3_Optional_Id], [l1.OneToOne_Required_FK1.OneToOne_Optional_FK2.OneToMany_Required3].[Level3_Required_Id], [l1.OneToOne_Required_FK1.OneToOne_Optional_FK2.OneToMany_Required3].[Name], [l1.OneToOne_Required_FK1.OneToOne_Optional_FK2.OneToMany_Required3].[OneToMany_Optional_Inverse4Id], [l1.OneToOne_Required_FK1.OneToOne_Optional_FK2.OneToMany_Required3].[OneToMany_Optional_Self_Inverse4Id], [l1.OneToOne_Required_FK1.OneToOne_Optional_FK2.OneToMany_Required3].[OneToMany_Required_Inverse4Id], [l1.OneToOne_Required_FK1.OneToOne_Optional_FK2.OneToMany_Required3].[OneToMany_Required_Self_Inverse4Id], [l1.OneToOne_Required_FK1.OneToOne_Optional_FK2.OneToMany_Required3].[OneToOne_Optional_PK_Inverse4Id], [l1.OneToOne_Required_FK1.OneToOne_Optional_FK2.OneToMany_Required3].[OneToOne_Optional_Self4Id], [l3.OneToOne_Optional_FK_Inverse3.OneToOne_Required_FK2].[Name] AS [Property], [t].[Id] //FROM [LevelOne] AS [l1] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs index 8c81b8f7950..537081d9e72 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs @@ -3318,7 +3318,7 @@ public class Configuration9468 #region Bug10635 - [ConditionalFact(Skip = "issue #15611")] + [ConditionalFact(Skip = "issue #14935")] public void Include_with_order_by_on_interface_key() { using (CreateDatabase10635()) @@ -3360,7 +3360,7 @@ FROM [Parents] AS [p0] } } - [ConditionalFact(Skip = "issue #15043")] + [ConditionalFact(Skip = "issue #14935")] public void Correlated_collection_with_order_by_on_interface_key() { using (CreateDatabase10635())