From 12174a13da4165056324e2e58fae63f3def62cd5 Mon Sep 17 00:00:00 2001 From: Maurycy Markowski Date: Fri, 6 Sep 2019 12:29:00 -0700 Subject: [PATCH] Fix to #17531 - Query: incorrect results for queries with optional navigation followed by collection navigation with skip/take/distinct Problem was that when expanding collection navigations we convert them into subqueries with a correlation predicate being outerKey == innerKey. For relational, most of those queries would later be converted into joins, however for some complex cases e.g. with Skip/Take (and also on InMemory) the query would stay in the form of subquery with correlation predicate. Then, null semantics kicks in and converts the correlation predicate to a form that returns true when both keys are null. This is incorrect in the context of chaining navigations - if the parent entity is null then it should never return any children. Fix is to add null check to the correlation predicate during nav rewrite, like so: outerKey != null && outerKey == innerKey Additionally, when trying to convert those subqueries into joins we need to account for a new pattern and remove the null check, since its irrelevant when it comes to join key comparison on relational --- ...yableMethodTranslatingExpressionVisitor.cs | 11 ++- ...yableMethodTranslatingExpressionVisitor.cs | 11 ++- .../Query/SqlExpressions/SelectExpression.cs | 50 +++++++++++--- ...ingExpressionVisitor.ExpressionVisitors.cs | 41 ++++++----- .../ComplexNavigationsQueryInMemoryTest.cs | 54 --------------- ...ComplexNavigationsWeakQueryInMemoryTest.cs | 42 ------------ .../Query/GearsOfWarQueryInMemoryTest.cs | 24 ------- .../Query/ComplexNavigationsQueryTestBase.cs | 4 +- .../Query/GearsOfWarQueryTestBase.cs | 68 ++++++++++++++++--- .../Query/IncludeTestBase.cs | 2 +- .../Query/QueryNavigationsTestBase.cs | 4 +- .../Query/GearsOfWarQuerySqlServerTest.cs | 49 +++++++++++-- .../Query/QueryNavigationsSqlServerTest.cs | 2 +- ...impleQuerySqlServerTest.KeylessEntities.cs | 2 +- .../ComplexNavigationsQuerySqliteTest.cs | 6 ++ .../ComplexNavigationsWeakQuerySqliteTest.cs | 6 ++ .../Query/GearsOfWarQuerySqliteTest.cs | 6 ++ 17 files changed, 209 insertions(+), 173 deletions(-) diff --git a/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs index 482cdf8e62a..9394da76a61 100644 --- a/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs @@ -933,8 +933,17 @@ private Expression Expand(Expression source, MemberIdentity member) : foreignKey.Properties, makeNullable); - var correlationPredicate = _expressionTranslator.Translate(Expression.Equal(outerKey, innerKey)); + var outerKeyFirstProperty = outerKey is NewExpression newExpression + ? ((UnaryExpression)((NewArrayExpression)newExpression.Arguments[0]).Expressions[0]).Operand + : outerKey; + var predicate = outerKeyFirstProperty.Type.IsNullableType() + ? Expression.AndAlso( + Expression.NotEqual(outerKeyFirstProperty, Expression.Constant(null, outerKeyFirstProperty.Type)), + Expression.Equal(outerKey, innerKey)) + : Expression.Equal(outerKey, innerKey); + + var correlationPredicate = _expressionTranslator.Translate(predicate); innerQueryExpression.ServerQueryExpression = Expression.Call( InMemoryLinqOperatorProvider.Where.MakeGenericMethod(innerQueryExpression.CurrentParameter.Type), innerQueryExpression.ServerQueryExpression, diff --git a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs index c2654e5aaa6..38af5516b9c 100644 --- a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs @@ -1122,8 +1122,17 @@ private Expression Expand(Expression source, MemberIdentity member) : foreignKey.Properties, makeNullable); - var correlationPredicate = _sqlTranslator.Translate(Expression.Equal(outerKey, innerKey)); + var outerKeyFirstProperty = outerKey is NewExpression newExpression + ? ((UnaryExpression)((NewArrayExpression)newExpression.Arguments[0]).Expressions[0]).Operand + : outerKey; + var predicate = outerKeyFirstProperty.Type.IsNullableType() + ? Expression.AndAlso( + Expression.NotEqual(outerKeyFirstProperty, Expression.Constant(null, outerKeyFirstProperty.Type)), + Expression.Equal(outerKey, innerKey)) + : Expression.Equal(outerKey, innerKey); + + var correlationPredicate = _sqlTranslator.Translate(predicate); innerSelectExpression.ApplyPredicate(correlationPredicate); return innerShapedQuery; diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs index 0a9d72dc250..0a772389fd4 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs @@ -921,6 +921,11 @@ private SqlExpression TryExtractJoinKey(SelectExpression selectExpression) && selectExpression.Predicate != null) { var joinPredicate = TryExtractJoinKey(selectExpression, selectExpression.Predicate, out var predicate); + if (predicate != null) + { + predicate = RemoveNullChecks(predicate); + } + selectExpression.Predicate = predicate; return joinPredicate; @@ -944,28 +949,28 @@ private SqlExpression TryExtractJoinKey( if (sqlBinaryExpression.OperatorType == ExpressionType.AndAlso) { - static SqlExpression combineNonNullExpressions(SqlExpression left, SqlExpression right) - { - return left != null - ? right != null - ? new SqlBinaryExpression(ExpressionType.AndAlso, left, right, left.Type, left.TypeMapping) - : left - : right; - } var leftJoinKey = TryExtractJoinKey(selectExpression, sqlBinaryExpression.Left, out var leftPredicate); var rightJoinKey = TryExtractJoinKey(selectExpression, sqlBinaryExpression.Right, out var rightPredicate); - updatedPredicate = combineNonNullExpressions(leftPredicate, rightPredicate); + updatedPredicate = CombineNonNullExpressions(leftPredicate, rightPredicate); - return combineNonNullExpressions(leftJoinKey, rightJoinKey); + return CombineNonNullExpressions(leftJoinKey, rightJoinKey); } } updatedPredicate = predicate; + return null; } + private static SqlExpression CombineNonNullExpressions(SqlExpression left, SqlExpression right) + => left != null + ? right != null + ? new SqlBinaryExpression(ExpressionType.AndAlso, left, right, left.Type, left.TypeMapping) + : left + : right; + private SqlBinaryExpression ValidateKeyComparison(SelectExpression inner, SqlBinaryExpression sqlBinaryExpression) { if (sqlBinaryExpression.OperatorType == ExpressionType.Equal) @@ -992,6 +997,31 @@ private SqlBinaryExpression ValidateKeyComparison(SelectExpression inner, SqlBin return null; } + private SqlExpression RemoveNullChecks(SqlExpression predicate) + { + if (predicate is SqlBinaryExpression sqlBinaryExpression) + { + if (sqlBinaryExpression.OperatorType == ExpressionType.NotEqual + && sqlBinaryExpression.Left is ColumnExpression leftColumn + && ContainsTableReference(leftColumn.Table) + && sqlBinaryExpression.Right is SqlConstantExpression sqlConstantExpression + && sqlConstantExpression.Value == null) + { + return null; + } + + if (sqlBinaryExpression.OperatorType == ExpressionType.AndAlso) + { + var leftPredicate = RemoveNullChecks(sqlBinaryExpression.Left); + var rightPredicate = RemoveNullChecks(sqlBinaryExpression.Right); + + return CombineNonNullExpressions(leftPredicate, rightPredicate); + } + } + + return predicate; + } + private bool ContainsTableReference(TableExpressionBase table) => Tables.Any(te => ReferenceEquals(te is JoinExpressionBase jeb ? jeb.Table : te, table)); diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs index 18631702f1c..02aba9698e6 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs @@ -179,11 +179,11 @@ protected Expression ExpandNavigation( { // This is FirstOrDefault ending so we need to push down properties. var temporaryParameter = Expression.Parameter(root.Type); - var temporaryKey = CreateKeyAccessExpression( - temporaryParameter, + var temporaryKey = temporaryParameter.CreateKeyAccessExpression( navigation.IsDependentToPrincipal() ? navigation.ForeignKey.Properties - : navigation.ForeignKey.PrincipalKey.Properties); + : navigation.ForeignKey.PrincipalKey.Properties, + makeNullable: true); var newSelector = ReplacingExpressionVisitor.Replace( temporaryParameter, innerNavigationExpansionExpression.PendingSelector, @@ -193,18 +193,18 @@ protected Expression ExpandNavigation( } else { - outerKey = CreateKeyAccessExpression( - root, + outerKey = root.CreateKeyAccessExpression( navigation.IsDependentToPrincipal() ? navigation.ForeignKey.Properties - : navigation.ForeignKey.PrincipalKey.Properties); + : navigation.ForeignKey.PrincipalKey.Properties, + makeNullable: true); } - var innerKey = CreateKeyAccessExpression( - innerParameter, + var innerKey = innerParameter.CreateKeyAccessExpression( navigation.IsDependentToPrincipal() ? navigation.ForeignKey.PrincipalKey.Properties - : navigation.ForeignKey.Properties); + : navigation.ForeignKey.Properties, + makeNullable: true); if (outerKey.Type != innerKey.Type) { @@ -221,14 +221,24 @@ protected Expression ExpandNavigation( if (navigation.IsCollection()) { + var outerKeyFirstProperty = outerKey is NewExpression newExpression + ? ((UnaryExpression)((NewArrayExpression)newExpression.Arguments[0]).Expressions[0]).Operand + : outerKey; + // This is intentionally deferred to be applied to innerSource.Source // Since outerKey's reference could change if a reference navigation is expanded afterwards + var predicateBody = outerKeyFirstProperty.Type.IsNullableType() + ? Expression.AndAlso( + Expression.NotEqual(outerKeyFirstProperty, Expression.Constant(null, outerKeyFirstProperty.Type)), + Expression.Equal(outerKey, innerKey)) + : Expression.Equal(outerKey, innerKey); + var subquery = Expression.Call( QueryableMethods.Where.MakeGenericMethod(innerSoureSequenceType), innerSource, Expression.Quote( Expression.Lambda( - Expression.Equal(outerKey, innerKey), innerParameter))); + predicateBody, innerParameter))); return new MaterializeCollectionNavigationExpression(subquery, navigation); } @@ -286,17 +296,6 @@ protected Expression ExpandNavigation( return innerSource.PendingSelector; } - - private static Expression CreateKeyAccessExpression(Expression target, IReadOnlyList properties) - => properties.Count == 1 - ? target.CreateEFPropertyExpression(properties[0]) - : Expression.New( - AnonymousObject.AnonymousObjectCtor, - Expression.NewArrayInit( - typeof(object), - properties - .Select(p => Expression.Convert(target.CreateEFPropertyExpression(p), typeof(object))) - .ToArray())); } private class IncludeExpandingExpressionVisitor : ExpandingExpressionVisitor diff --git a/test/EFCore.InMemory.FunctionalTests/Query/ComplexNavigationsQueryInMemoryTest.cs b/test/EFCore.InMemory.FunctionalTests/Query/ComplexNavigationsQueryInMemoryTest.cs index b55714760bf..f043039dee6 100644 --- a/test/EFCore.InMemory.FunctionalTests/Query/ComplexNavigationsQueryInMemoryTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/Query/ComplexNavigationsQueryInMemoryTest.cs @@ -15,64 +15,10 @@ public ComplexNavigationsQueryInMemoryTest(ComplexNavigationsQueryInMemoryFixtur //TestLoggerFactory.TestOutputHelper = testOutputHelper; } - [ConditionalTheory(Skip = "issue #17531")] - public override Task SelectMany_with_nested_navigations_and_explicit_DefaultIfEmpty_followed_by_Select_required_navigation_using_different_navs(bool isAsync) - { - return base.SelectMany_with_nested_navigations_and_explicit_DefaultIfEmpty_followed_by_Select_required_navigation_using_different_navs(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task SelectMany_with_nested_navigation_and_explicit_DefaultIfEmpty(bool isAsync) - { - return base.SelectMany_with_nested_navigation_and_explicit_DefaultIfEmpty(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task SelectMany_with_nested_navigation_filter_and_explicit_DefaultIfEmpty(bool isAsync) - { - return base.SelectMany_with_nested_navigation_filter_and_explicit_DefaultIfEmpty(isAsync); - } - [ConditionalTheory(Skip = "issue #17386")] public override Task Complex_query_with_optional_navigations_and_client_side_evaluation(bool isAsync) { return base.Complex_query_with_optional_navigations_and_client_side_evaluation(isAsync); } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task Project_collection_navigation_nested(bool isAsync) - { - return base.Project_collection_navigation_nested(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task Project_collection_navigation_nested_anonymous(bool isAsync) - { - return base.Project_collection_navigation_nested_anonymous(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task Project_collection_navigation_using_ef_property(bool isAsync) - { - return base.Project_collection_navigation_using_ef_property(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task Project_navigation_and_collection(bool isAsync) - { - return base.Project_navigation_and_collection(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task SelectMany_nested_navigation_property_optional_and_projection(bool isAsync) - { - return base.SelectMany_nested_navigation_property_optional_and_projection(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task SelectMany_nested_navigation_property_required(bool isAsync) - { - return base.SelectMany_nested_navigation_property_required(isAsync); - } } } diff --git a/test/EFCore.InMemory.FunctionalTests/Query/ComplexNavigationsWeakQueryInMemoryTest.cs b/test/EFCore.InMemory.FunctionalTests/Query/ComplexNavigationsWeakQueryInMemoryTest.cs index 51713052d35..f86b5a7679b 100644 --- a/test/EFCore.InMemory.FunctionalTests/Query/ComplexNavigationsWeakQueryInMemoryTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/Query/ComplexNavigationsWeakQueryInMemoryTest.cs @@ -24,48 +24,6 @@ public override Task Complex_query_with_optional_navigations_and_client_side_eva return base.Complex_query_with_optional_navigations_and_client_side_evaluation(isAsync); } - [ConditionalTheory(Skip = "issue #17531")] - public override Task SelectMany_with_nested_navigations_and_explicit_DefaultIfEmpty_followed_by_Select_required_navigation_using_different_navs(bool isAsync) - { - return base.SelectMany_with_nested_navigations_and_explicit_DefaultIfEmpty_followed_by_Select_required_navigation_using_different_navs(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task SelectMany_with_nested_navigation_filter_and_explicit_DefaultIfEmpty(bool isAsync) - { - return base.SelectMany_with_nested_navigation_filter_and_explicit_DefaultIfEmpty(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task Project_collection_navigation_nested(bool isAsync) - { - return base.Project_collection_navigation_nested(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task Project_collection_navigation_nested_anonymous(bool isAsync) - { - return base.Project_collection_navigation_nested_anonymous(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task Project_collection_navigation_using_ef_property(bool isAsync) - { - return base.Project_collection_navigation_using_ef_property(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task Project_navigation_and_collection(bool isAsync) - { - return base.Project_navigation_and_collection(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task SelectMany_nested_navigation_property_optional_and_projection(bool isAsync) - { - return base.SelectMany_nested_navigation_property_optional_and_projection(isAsync); - } - [ConditionalTheory(Skip = "17539")] public override Task Join_navigations_in_inner_selector_translated_without_collision(bool isAsync) { diff --git a/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs b/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs index 417930e261a..0fc031a5ab2 100644 --- a/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs @@ -45,30 +45,6 @@ public override Task GetValueOrDefault_on_DateTimeOffset(bool isAsync) return base.GetValueOrDefault_on_DateTimeOffset(isAsync); } - [ConditionalTheory(Skip = "issue #17531")] - public override Task Correlated_collection_with_complex_OrderBy(bool isAsync) - { - return base.Correlated_collection_with_complex_OrderBy(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task Correlated_collection_with_very_complex_order_by(bool isAsync) - { - return base.Correlated_collection_with_very_complex_order_by(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task Include_collection_OrderBy_aggregate(bool isAsync) - { - return base.Include_collection_OrderBy_aggregate(isAsync); - } - - [ConditionalTheory(Skip = "issue #17531")] - public override Task Include_collection_with_complex_OrderBy3(bool isAsync) - { - return base.Include_collection_with_complex_OrderBy3(isAsync); - } - [ConditionalFact(Skip = "issue #17537")] public override void Include_on_GroupJoin_SelectMany_DefaultIfEmpty_with_coalesce_result1() { diff --git a/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs index f1d6342c6fc..f92af02b675 100644 --- a/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs @@ -4450,7 +4450,7 @@ select Maybe(l1.OneToOne_Optional_FK1, () => l1.OneToOne_Optional_FK1.OneToMany_ }); } - [ConditionalTheory(Skip = "issue #17531")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Project_collection_navigation_nested_with_take(bool isAsync) { @@ -4460,7 +4460,7 @@ public virtual Task Project_collection_navigation_nested_with_take(bool isAsync) select l1.OneToOne_Optional_FK1.OneToMany_Optional2.Take(50), l1s => from l1 in l1s select Maybe(l1.OneToOne_Optional_FK1, () => l1.OneToOne_Optional_FK1.OneToMany_Optional2.Take(50)), - elementSorter: e => e != null ? e.Count : 0, + elementSorter: e => ((IEnumerable)e)?.Count() ?? 0, elementAsserter: (e, a) => { var actualCollection = new List(); diff --git a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs index 9fcb33ebcbf..71ad4995879 100644 --- a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs @@ -1753,7 +1753,7 @@ public virtual async Task Select_navigation_with_concat_and_count(bool isAsync) gs => gs.Where(g => !g.HasSoulPatch).Select(g => g.Weapons.Concat(g.Weapons).Count())))).Message; Assert.Equal( - RemoveNewLines(CoreStrings.QueryFailed("Concat(\n source1: AsQueryable(MaterializeCollectionNavigation(Navigation: Gear.Weapons (k__BackingField, ICollection) Collection ToDependent Weapon Inverse: Owner, Where(\n source: NavigationExpansionExpression\n Source: Where(\n source: DbSet, \n predicate: (w) => Property((Unhandled parameter: g), \"FullName\") == Property(w, \"OwnerFullName\"))\n PendingSelector: (w) => NavigationTreeExpression\n Value: EntityReferenceWeapon\n Expression: w\n , \n predicate: (i) => Property(NavigationTreeExpression\n Value: EntityReferenceGear\n Expression: (Unhandled parameter: g), \"FullName\") == Property(i, \"OwnerFullName\")))), \n source2: MaterializeCollectionNavigation(Navigation: Gear.Weapons (k__BackingField, ICollection) Collection ToDependent Weapon Inverse: Owner, Where(\n source: NavigationExpansionExpression\n Source: Where(\n source: DbSet, \n predicate: (w0) => Property((Unhandled parameter: g), \"FullName\") == Property(w0, \"OwnerFullName\"))\n PendingSelector: (w0) => NavigationTreeExpression\n Value: EntityReferenceWeapon\n Expression: w0\n , \n predicate: (i) => Property(NavigationTreeExpression\n Value: EntityReferenceGear\n Expression: (Unhandled parameter: g), \"FullName\") == Property(i, \"OwnerFullName\"))))", "NavigationExpandingExpressionVisitor")), + CoreStrings.QueryFailed("Concat( source1: AsQueryable(MaterializeCollectionNavigation(Navigation: Gear.Weapons (k__BackingField, ICollection) Collection ToDependent Weapon Inverse: Owner, Where( source: NavigationExpansionExpression Source: Where( source: DbSet, predicate: (w) => Property((Unhandled parameter: g), \"FullName\") != null && Property((Unhandled parameter: g), \"FullName\") == Property(w, \"OwnerFullName\")) PendingSelector: (w) => NavigationTreeExpression Value: EntityReferenceWeapon Expression: w , predicate: (i) => Property(NavigationTreeExpression Value: EntityReferenceGear Expression: (Unhandled parameter: g), \"FullName\") != null && Property(NavigationTreeExpression Value: EntityReferenceGear Expression: (Unhandled parameter: g), \"FullName\") == Property(i, \"OwnerFullName\")))), source2: MaterializeCollectionNavigation(Navigation: Gear.Weapons (k__BackingField, ICollection) Collection ToDependent Weapon Inverse: Owner, Where( source: NavigationExpansionExpression Source: Where( source: DbSet, predicate: (w0) => Property((Unhandled parameter: g), \"FullName\") != null && Property((Unhandled parameter: g), \"FullName\") == Property(w0, \"OwnerFullName\")) PendingSelector: (w0) => NavigationTreeExpression Value: EntityReferenceWeapon Expression: w0 , predicate: (i) => Property(NavigationTreeExpression Value: EntityReferenceGear Expression: (Unhandled parameter: g), \"FullName\") != null && Property(NavigationTreeExpression Value: EntityReferenceGear Expression: (Unhandled parameter: g), \"FullName\") == Property(i, \"OwnerFullName\"))))", "NavigationExpandingExpressionVisitor"), RemoveNewLines(message)); } @@ -1778,7 +1778,7 @@ public virtual async Task Concat_with_collection_navigations(bool isAsync) gs => gs.Where(g => g.HasSoulPatch).Select(g => g.Weapons.Union(g.Weapons).Count())))).Message; Assert.Equal( - RemoveNewLines(CoreStrings.QueryFailed("Union(\n source1: AsQueryable(MaterializeCollectionNavigation(Navigation: Gear.Weapons (k__BackingField, ICollection) Collection ToDependent Weapon Inverse: Owner, Where(\n source: NavigationExpansionExpression\n Source: Where(\n source: DbSet, \n predicate: (w) => Property((Unhandled parameter: g), \"FullName\") == Property(w, \"OwnerFullName\"))\n PendingSelector: (w) => NavigationTreeExpression\n Value: EntityReferenceWeapon\n Expression: w\n , \n predicate: (i) => Property(NavigationTreeExpression\n Value: EntityReferenceGear\n Expression: (Unhandled parameter: g), \"FullName\") == Property(i, \"OwnerFullName\")))), \n source2: MaterializeCollectionNavigation(Navigation: Gear.Weapons (k__BackingField, ICollection) Collection ToDependent Weapon Inverse: Owner, Where(\n source: NavigationExpansionExpression\n Source: Where(\n source: DbSet, \n predicate: (w0) => Property((Unhandled parameter: g), \"FullName\") == Property(w0, \"OwnerFullName\"))\n PendingSelector: (w0) => NavigationTreeExpression\n Value: EntityReferenceWeapon\n Expression: w0\n , \n predicate: (i) => Property(NavigationTreeExpression\n Value: EntityReferenceGear\n Expression: (Unhandled parameter: g), \"FullName\") == Property(i, \"OwnerFullName\"))))", "NavigationExpandingExpressionVisitor")), + CoreStrings.QueryFailed("Union( source1: AsQueryable(MaterializeCollectionNavigation(Navigation: Gear.Weapons (k__BackingField, ICollection) Collection ToDependent Weapon Inverse: Owner, Where( source: NavigationExpansionExpression Source: Where( source: DbSet, predicate: (w) => Property((Unhandled parameter: g), \"FullName\") != null && Property((Unhandled parameter: g), \"FullName\") == Property(w, \"OwnerFullName\")) PendingSelector: (w) => NavigationTreeExpression Value: EntityReferenceWeapon Expression: w , predicate: (i) => Property(NavigationTreeExpression Value: EntityReferenceGear Expression: (Unhandled parameter: g), \"FullName\") != null && Property(NavigationTreeExpression Value: EntityReferenceGear Expression: (Unhandled parameter: g), \"FullName\") == Property(i, \"OwnerFullName\")))), source2: MaterializeCollectionNavigation(Navigation: Gear.Weapons (k__BackingField, ICollection) Collection ToDependent Weapon Inverse: Owner, Where( source: NavigationExpansionExpression Source: Where( source: DbSet, predicate: (w0) => Property((Unhandled parameter: g), \"FullName\") != null && Property((Unhandled parameter: g), \"FullName\") == Property(w0, \"OwnerFullName\")) PendingSelector: (w0) => NavigationTreeExpression Value: EntityReferenceWeapon Expression: w0 , predicate: (i) => Property(NavigationTreeExpression Value: EntityReferenceGear Expression: (Unhandled parameter: g), \"FullName\") != null && Property(NavigationTreeExpression Value: EntityReferenceGear Expression: (Unhandled parameter: g), \"FullName\") == Property(i, \"OwnerFullName\"))))", "NavigationExpandingExpressionVisitor"), RemoveNewLines(message)); } @@ -3426,7 +3426,7 @@ public virtual async Task Client_method_on_collection_navigation_in_predicate(bo select g.Nickname))).Message; Assert.Equal( - CoreStrings.TranslationFailed("Where( source: DbSet, predicate: (g) => g.HasSoulPatch && FavoriteWeapon(MaterializeCollectionNavigation(Navigation: Gear.Weapons (k__BackingField, ICollection) Collection ToDependent Weapon Inverse: Owner, Where( source: DbSet, predicate: (w) => Property(g, \"FullName\") == Property(w, \"OwnerFullName\")))).Name == \"Marcus' Lancer\")"), + CoreStrings.TranslationFailed("Where( source: DbSet, predicate: (g) => g.HasSoulPatch && FavoriteWeapon(MaterializeCollectionNavigation(Navigation: Gear.Weapons (k__BackingField, ICollection) Collection ToDependent Weapon Inverse: Owner, Where( source: DbSet, predicate: (w) => Property(g, \"FullName\") != null && Property(g, \"FullName\") == Property(w, \"OwnerFullName\")))).Name == \"Marcus' Lancer\")"), RemoveNewLines(message)); } @@ -3445,7 +3445,7 @@ public virtual async Task Client_method_on_collection_navigation_in_predicate_ac select g.Nickname))).Message; Assert.Equal( - CoreStrings.TranslationFailed("Where( source: DbSet, predicate: (g) => !(g.HasSoulPatch) && FavoriteWeapon(MaterializeCollectionNavigation(Navigation: Gear.Weapons (k__BackingField, ICollection) Collection ToDependent Weapon Inverse: Owner, Where( source: DbSet, predicate: (w) => Property(g, \"FullName\") == Property(w, \"OwnerFullName\")))).Name == \"Cole's Gnasher\")"), + CoreStrings.TranslationFailed("Where( source: DbSet, predicate: (g) => !(g.HasSoulPatch) && FavoriteWeapon(MaterializeCollectionNavigation(Navigation: Gear.Weapons (k__BackingField, ICollection) Collection ToDependent Weapon Inverse: Owner, Where( source: DbSet, predicate: (w) => Property(g, \"FullName\") != null && Property(g, \"FullName\") == Property(w, \"OwnerFullName\")))).Name == \"Cole's Gnasher\")"), RemoveNewLines(message)); } @@ -3463,7 +3463,7 @@ orderby FavoriteWeapon(g.Weapons).Name descending assertOrder: true))).Message; Assert.Equal( - CoreStrings.TranslationFailed("OrderByDescending( source: Where( source: DbSet, predicate: (g) => !(g.HasSoulPatch)), keySelector: (g) => FavoriteWeapon(MaterializeCollectionNavigation(Navigation: Gear.Weapons (k__BackingField, ICollection) Collection ToDependent Weapon Inverse: Owner, Where( source: DbSet, predicate: (w) => Property(g, \"FullName\") == Property(w, \"OwnerFullName\")))).Name)"), + CoreStrings.TranslationFailed("OrderByDescending( source: Where( source: DbSet, predicate: (g) => !(g.HasSoulPatch)), keySelector: (g) => FavoriteWeapon(MaterializeCollectionNavigation(Navigation: Gear.Weapons (k__BackingField, ICollection) Collection ToDependent Weapon Inverse: Owner, Where( source: DbSet, predicate: (w) => Property(g, \"FullName\") != null && Property(g, \"FullName\") == Property(w, \"OwnerFullName\")))).Name)"), RemoveNewLines(message)); } @@ -6543,7 +6543,7 @@ public virtual Task Include_collection_OrderBy_aggregate(bool isAsync) isAsync, os => os.OfType() .Include(o => o.Reports) - .OrderBy(o => o.Weapons.Count), + .OrderBy(o => o.Weapons.Count).ThenBy(o => o.Nickname), new List { new ExpectedInclude(o => o.Reports, "Reports") @@ -6575,7 +6575,7 @@ public virtual Task Include_collection_with_complex_OrderBy3(bool isAsync) isAsync, os => os.OfType() .Include(o => o.Reports) - .OrderBy(o => o.Weapons.OrderBy(w => w.Id).Select(w => w.IsAutomatic).FirstOrDefault()), + .OrderBy(o => o.Weapons.OrderBy(w => w.Id).Select(w => w.IsAutomatic).FirstOrDefault()).ThenBy(o => o.Nickname), new List { new ExpectedInclude(o => o.Reports, "Reports") @@ -6590,7 +6590,7 @@ public virtual Task Correlated_collection_with_complex_OrderBy(bool isAsync) return AssertQuery( isAsync, gs => gs.OfType() - .OrderBy(o => o.Weapons.Count) + .OrderBy(o => o.Weapons.Count).ThenBy(g => g.Nickname) .Select(o => o.Reports.Where(g => !g.HasSoulPatch).ToList()), assertOrder: true, elementAsserter: CollectionAsserter(ee => ee.FullName, (ee, aa) => Assert.Equal(ee.FullName, aa.FullName))); @@ -6606,7 +6606,7 @@ public virtual Task Correlated_collection_with_very_complex_order_by(bool isAsyn .OrderBy( o => o.Weapons.Where( w => w.IsAutomatic == gs.Where(g => g.Nickname == "Marcus").Select(g => g.HasSoulPatch).FirstOrDefault()) - .Count()) + .Count()).ThenBy(g => g.Nickname) .Select(o => o.Reports.Where(g => !g.HasSoulPatch).ToList()), assertOrder: true, elementAsserter: CollectionAsserter(ee => ee.FullName, (ee, aa) => Assert.Equal(ee.FullName, aa.FullName))); @@ -7570,6 +7570,56 @@ orderby g.Nickname select new { Nickname1 = g.Nickname, Nickname2 = o.Nickname }); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Project_collection_navigation_nested_with_take_composite_key(bool isAsync) + { + return AssertQuery( + isAsync, + ts => from t in ts + where t.Gear is Officer + select ((Officer)t.Gear).Reports.Take(50), + ts => from t in ts + where t.Gear is Officer + select Maybe(t.Gear, () => ((Officer)t.Gear).Reports.Take(50)), + elementSorter: e => ((IEnumerable)e)?.Count() ?? 0, + elementAsserter: (e, a) => + { + var actualCollection = new List(); + foreach (var actualElement in a) + { + actualCollection.Add(actualElement); + } + + Assert.Equal(((IEnumerable)e)?.Count() ?? 0, actualCollection.Count); + }); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Project_collection_navigation_nested_composite_key(bool isAsync) + { + return AssertQuery( + isAsync, + ts => from t in ts + where t.Gear is Officer + select ((Officer)t.Gear).Reports, + ts => from t in ts + where t.Gear is Officer + select Maybe(t.Gear, () => ((Officer)t.Gear).Reports), + elementSorter: e => ((IEnumerable)e)?.Count() ?? 0, + elementAsserter: (e, a) => + { + var actualCollection = new List(); + foreach (var actualElement in a) + { + actualCollection.Add(actualElement); + } + + Assert.Equal(((IEnumerable)e)?.Count() ?? 0, actualCollection.Count); + }); + } + protected GearsOfWarContext CreateContext() => Fixture.CreateContext(); protected virtual void ClearLog() diff --git a/test/EFCore.Specification.Tests/Query/IncludeTestBase.cs b/test/EFCore.Specification.Tests/Query/IncludeTestBase.cs index bdb2103251d..1054e9ef5ac 100644 --- a/test/EFCore.Specification.Tests/Query/IncludeTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/IncludeTestBase.cs @@ -363,7 +363,7 @@ public virtual void Include_collection_with_last_no_orderby(bool useString) { Assert.Equal( CoreStrings.TranslationFailed( - @"Last(Select( source: DbSet, selector: (c) => IncludeExpression( c, MaterializeCollectionNavigation(Navigation: Customer.Orders (k__BackingField, List) Collection ToDependent Order Inverse: Customer PropertyAccessMode.Field, Where( source: DbSet, predicate: (o) => Property(c, ""CustomerID"") == Property(o, ""CustomerID""))), Orders)))"), + "Last(Select( source: DbSet, selector: (c) => IncludeExpression( c, MaterializeCollectionNavigation(Navigation: Customer.Orders (k__BackingField, List) Collection ToDependent Order Inverse: Customer PropertyAccessMode.Field, Where( source: DbSet, predicate: (o) => Property(c, \"CustomerID\") != null && Property(c, \"CustomerID\") == Property(o, \"CustomerID\"))), Orders)))"), RemoveNewLines( Assert.Throws( () => useString diff --git a/test/EFCore.Specification.Tests/Query/QueryNavigationsTestBase.cs b/test/EFCore.Specification.Tests/Query/QueryNavigationsTestBase.cs index e3be9f95ea2..985ac639703 100644 --- a/test/EFCore.Specification.Tests/Query/QueryNavigationsTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/QueryNavigationsTestBase.cs @@ -669,7 +669,7 @@ public virtual Task Collection_select_nav_prop_all(bool isAsync) public virtual async Task Collection_select_nav_prop_all_client(bool isAsync) { Assert.Equal( - CoreStrings.TranslationFailed("All( source: Where( source: DbSet, predicate: (o0) => Property(EntityShaperExpression: EntityType: Customer ValueBufferExpression: ProjectionBindingExpression: EmptyProjectionMember IsNullable: False , \"CustomerID\") == Property(o0, \"CustomerID\")), predicate: (o0) => o0.ShipCity == \"London\")"), + CoreStrings.TranslationFailed("All( source: Where( source: DbSet, predicate: (o0) => Property(EntityShaperExpression: EntityType: Customer ValueBufferExpression: ProjectionBindingExpression: EmptyProjectionMember IsNullable: False , \"CustomerID\") != null && Property(EntityShaperExpression: EntityType: Customer ValueBufferExpression: ProjectionBindingExpression: EmptyProjectionMember IsNullable: False , \"CustomerID\") == Property(o0, \"CustomerID\")), predicate: (o0) => o0.ShipCity == \"London\")"), RemoveNewLines((await Assert.ThrowsAsync( () => AssertQuery( isAsync, @@ -710,7 +710,7 @@ public virtual void Collection_where_nav_prop_all_client() { Assert.Equal( CoreStrings.TranslationFailed( - "All( source: Where( source: DbSet, predicate: (o) => Property(EntityShaperExpression: EntityType: Customer ValueBufferExpression: ProjectionBindingExpression: EmptyProjectionMember IsNullable: False , \"CustomerID\") == Property(o, \"CustomerID\")), predicate: (o) => o.ShipCity == \"London\")"), + "All( source: Where( source: DbSet, predicate: (o) => Property(EntityShaperExpression: EntityType: Customer ValueBufferExpression: ProjectionBindingExpression: EmptyProjectionMember IsNullable: False , \"CustomerID\") != null && Property(EntityShaperExpression: EntityType: Customer ValueBufferExpression: ProjectionBindingExpression: EmptyProjectionMember IsNullable: False , \"CustomerID\") == Property(o, \"CustomerID\")), predicate: (o) => o.ShipCity == \"London\")"), RemoveNewLines( Assert.Throws( () => (from c in context.Set() diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index f0d79e79edc..912b14b3460 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -3595,7 +3595,7 @@ WHERE [g].[Discriminator] IN (N'Gear', N'Officer') WHERE (([t0].[Discriminator] = N'Officer') AND [t0].[Discriminator] IS NOT NULL) AND (( SELECT COUNT(*) FROM [Gears] AS [g0] - WHERE ([g0].[Discriminator] IN (N'Gear', N'Officer') AND (((([t0].[Nickname] = [g0].[LeaderNickname]) AND ([t0].[Nickname] IS NOT NULL AND [g0].[LeaderNickname] IS NOT NULL)) OR ([t0].[Nickname] IS NULL AND [g0].[LeaderNickname] IS NULL)) AND (([t0].[SquadId] = [g0].[LeaderSquadId]) AND [t0].[SquadId] IS NOT NULL))) AND ([g0].[Nickname] = N'Dom')) > 0)"); + WHERE ([g0].[Discriminator] IN (N'Gear', N'Officer') AND ([t0].[Nickname] IS NOT NULL AND (((([t0].[Nickname] = [g0].[LeaderNickname]) AND ([t0].[Nickname] IS NOT NULL AND [g0].[LeaderNickname] IS NOT NULL)) OR ([t0].[Nickname] IS NULL AND [g0].[LeaderNickname] IS NULL)) AND (([t0].[SquadId] = [g0].[LeaderSquadId]) AND [t0].[SquadId] IS NOT NULL)))) AND ([g0].[Nickname] = N'Dom')) > 0)"); } public override void Select_null_conditional_with_inheritance() @@ -4435,8 +4435,7 @@ WHERE [g2].[Discriminator] IN (N'Gear', N'Officer') AND ((([g].[Nickname] = [g2] ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t2].[IsAutomatic], [t2].[Nickname] DESC, [t2].[Id]"); } - public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery_complex_orderings( - bool isAsync) + public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery_complex_orderings(bool isAsync) { await base.Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery_complex_orderings(isAsync); @@ -4453,7 +4452,7 @@ LEFT JOIN ( SELECT [w0].[Id], [w0].[AmmunitionType], [w0].[IsAutomatic], [w0].[Name], [w0].[OwnerFullName], [w0].[SynergyWithId], ( SELECT COUNT(*) FROM [Weapons] AS [w] - WHERE (([t1].[FullName] = [w].[OwnerFullName]) AND ([t1].[FullName] IS NOT NULL AND [w].[OwnerFullName] IS NOT NULL)) OR ([t1].[FullName] IS NULL AND [w].[OwnerFullName] IS NULL)) AS [c] + WHERE [t1].[FullName] IS NOT NULL AND ((([t1].[FullName] = [w].[OwnerFullName]) AND ([t1].[FullName] IS NOT NULL AND [w].[OwnerFullName] IS NOT NULL)) OR ([t1].[FullName] IS NULL AND [w].[OwnerFullName] IS NULL))) AS [c] FROM [Weapons] AS [w0] LEFT JOIN ( SELECT [g1].[Nickname], [g1].[SquadId], [g1].[AssignedCityName], [g1].[CityOrBirthName], [g1].[Discriminator], [g1].[FullName], [g1].[HasSoulPatch], [g1].[LeaderNickname], [g1].[LeaderSquadId], [g1].[Rank] @@ -6911,6 +6910,48 @@ WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Nickname] = [t].[N ORDER BY [g].[Nickname]"); } + public override async Task Project_collection_navigation_nested_with_take_composite_key(bool isAsync) + { + await base.Project_collection_navigation_nested_with_take_composite_key(isAsync); + + AssertSql( + @"SELECT [t].[Id], [t1].[Nickname], [t1].[SquadId], [t1].[AssignedCityName], [t1].[CityOrBirthName], [t1].[Discriminator], [t1].[FullName], [t1].[HasSoulPatch], [t1].[LeaderNickname], [t1].[LeaderSquadId], [t1].[Rank] +FROM [Tags] AS [t] +LEFT JOIN ( + SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] + FROM [Gears] AS [g] + WHERE [g].[Discriminator] IN (N'Gear', N'Officer') +) AS [t0] ON (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) +OUTER APPLY ( + SELECT TOP(50) [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOrBirthName], [g0].[Discriminator], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') AND ([t0].[Nickname] IS NOT NULL AND (((([t0].[Nickname] = [g0].[LeaderNickname]) AND ([t0].[Nickname] IS NOT NULL AND [g0].[LeaderNickname] IS NOT NULL)) OR ([t0].[Nickname] IS NULL AND [g0].[LeaderNickname] IS NULL)) AND (([t0].[SquadId] = [g0].[LeaderSquadId]) AND [t0].[SquadId] IS NOT NULL))) +) AS [t1] +WHERE ([t0].[Discriminator] = N'Officer') AND [t0].[Discriminator] IS NOT NULL +ORDER BY [t].[Id], [t1].[Nickname], [t1].[SquadId]"); + } + + public override async Task Project_collection_navigation_nested_composite_key(bool isAsync) + { + await base.Project_collection_navigation_nested_composite_key(isAsync); + + AssertSql( + @"SELECT [t].[Id], [t1].[Nickname], [t1].[SquadId], [t1].[AssignedCityName], [t1].[CityOrBirthName], [t1].[Discriminator], [t1].[FullName], [t1].[HasSoulPatch], [t1].[LeaderNickname], [t1].[LeaderSquadId], [t1].[Rank] +FROM [Tags] AS [t] +LEFT JOIN ( + SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] + FROM [Gears] AS [g] + WHERE [g].[Discriminator] IN (N'Gear', N'Officer') +) AS [t0] ON (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN ( + SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOrBirthName], [g0].[Discriminator], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') +) AS [t1] ON ((([t0].[Nickname] = [t1].[LeaderNickname]) AND ([t0].[Nickname] IS NOT NULL AND [t1].[LeaderNickname] IS NOT NULL)) OR ([t0].[Nickname] IS NULL AND [t1].[LeaderNickname] IS NULL)) AND (([t0].[SquadId] = [t1].[LeaderSquadId]) AND [t0].[SquadId] IS NOT NULL) +WHERE ([t0].[Discriminator] = N'Officer') AND [t0].[Discriminator] IS NOT NULL +ORDER BY [t].[Id], [t1].[Nickname], [t1].[SquadId]"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/QueryNavigationsSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/QueryNavigationsSqlServerTest.cs index 3e9d4813c7d..1d3e615d3f3 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/QueryNavigationsSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/QueryNavigationsSqlServerTest.cs @@ -1011,7 +1011,7 @@ FROM [Orders] AS [o] WHERE ( SELECT COUNT(*) FROM [Orders] AS [o0] - WHERE ((([c].[CustomerID] = [o0].[CustomerID]) AND ([c].[CustomerID] IS NOT NULL AND [o0].[CustomerID] IS NOT NULL)) OR ([c].[CustomerID] IS NULL AND [o0].[CustomerID] IS NULL)) AND ([o0].[OrderID] > 10260)) > 30"); + WHERE ([c].[CustomerID] IS NOT NULL AND ((([c].[CustomerID] = [o0].[CustomerID]) AND ([c].[CustomerID] IS NOT NULL AND [o0].[CustomerID] IS NOT NULL)) OR ([c].[CustomerID] IS NULL AND [o0].[CustomerID] IS NULL))) AND ([o0].[OrderID] > 10260)) > 30"); } public override async Task Client_groupjoin_with_orderby_key_descending(bool isAsync) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.KeylessEntities.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.KeylessEntities.cs index 324bc24390a..e375c612ec2 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.KeylessEntities.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.KeylessEntities.cs @@ -125,7 +125,7 @@ public override async Task KeylessEntity_select_where_navigation_multi_level(boo WHERE EXISTS ( SELECT 1 FROM [Orders] AS [o0] - WHERE (([c].[CustomerID] = [o0].[CustomerID]) AND ([c].[CustomerID] IS NOT NULL AND [o0].[CustomerID] IS NOT NULL)) OR ([c].[CustomerID] IS NULL AND [o0].[CustomerID] IS NULL))"); + WHERE [c].[CustomerID] IS NOT NULL AND ((([c].[CustomerID] = [o0].[CustomerID]) AND ([c].[CustomerID] IS NOT NULL AND [o0].[CustomerID] IS NOT NULL)) OR ([c].[CustomerID] IS NULL AND [o0].[CustomerID] IS NULL)))"); } [ConditionalFact] diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/ComplexNavigationsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/ComplexNavigationsQuerySqliteTest.cs index 18565beff2b..a58f8dae5e2 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/ComplexNavigationsQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/ComplexNavigationsQuerySqliteTest.cs @@ -18,5 +18,11 @@ public override Task SelectMany_with_navigation_filter_paging_and_explicit_Defau { return base.SelectMany_with_navigation_filter_paging_and_explicit_DefaultIfEmpty(isAsync); } + + [ConditionalTheory(Skip = "Issue #17230")] + public override Task Project_collection_navigation_nested_with_take(bool isAsync) + { + return base.Project_collection_navigation_nested_with_take(isAsync); + } } } diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/ComplexNavigationsWeakQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/ComplexNavigationsWeakQuerySqliteTest.cs index a66fea32a0d..d9e2231a47b 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/ComplexNavigationsWeakQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/ComplexNavigationsWeakQuerySqliteTest.cs @@ -19,5 +19,11 @@ public override Task SelectMany_with_navigation_filter_paging_and_explicit_Defau { return base.SelectMany_with_navigation_filter_paging_and_explicit_DefaultIfEmpty(isAsync); } + + [ConditionalTheory(Skip = "Issue #17230")] + public override Task Project_collection_navigation_nested_with_take(bool isAsync) + { + return base.Project_collection_navigation_nested_with_take(isAsync); + } } } diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs index c4b97302749..7e8e8dc0d9d 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs @@ -154,5 +154,11 @@ private string RemoveNewLines(string message) public override Task Outer_parameter_in_join_key(bool isAsync) => null; public override Task Outer_parameter_in_join_key_inner_and_outer(bool isAsync) => null; + + [ConditionalTheory(Skip = "Issue #17230")] + public override Task Project_collection_navigation_nested_with_take_composite_key(bool isAsync) + { + return base.Project_collection_navigation_nested_with_take_composite_key(isAsync); + } } }