diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs index 22724d93a0b..a2eddc1380f 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs @@ -3542,25 +3542,58 @@ static List ExtractColumnsFromProjectionMapping( static SqlExpression? RemoveRedundantNullChecks(SqlExpression predicate, List outerColumnExpressions) { - if (predicate is SqlBinaryExpression sqlBinaryExpression) + // A single key comparison join predicate is processed with SQL null semantics in SqlNullabilityProcessor, so the + // outer key null check is genuinely redundant and is removed. But when the predicate is compound (e.g. the collection + // navigation has an additional filter), it's expanded with C# null semantics, which would incorrectly match rows where + // both keys are null. In that case the null check on a nullable outer key (e.g. the principal entity is reached through + // an optional navigation) must be kept to suppress that compensation. See #35706. + var keepNullableKeyChecks = CountNonNullCheckConjuncts(predicate, outerColumnExpressions) > 1; + + return Rewrite(predicate, outerColumnExpressions, keepNullableKeyChecks); + + static SqlExpression? Rewrite( + SqlExpression predicate, List outerColumnExpressions, bool keepNullableKeyChecks) { - if (sqlBinaryExpression.OperatorType == ExpressionType.NotEqual - && outerColumnExpressions.Contains(sqlBinaryExpression.Left) - && sqlBinaryExpression.Right is SqlConstantExpression { Value: null }) + if (predicate is SqlBinaryExpression sqlBinaryExpression) { - return null; - } + if (sqlBinaryExpression.OperatorType == ExpressionType.NotEqual + && outerColumnExpressions.Contains(sqlBinaryExpression.Left) + && sqlBinaryExpression.Right is SqlConstantExpression { Value: null } + && !(keepNullableKeyChecks && sqlBinaryExpression.Left is ColumnExpression { IsNullable: true })) + { + return null; + } - if (sqlBinaryExpression.OperatorType == ExpressionType.AndAlso) - { - var leftPredicate = RemoveRedundantNullChecks(sqlBinaryExpression.Left, outerColumnExpressions); - var rightPredicate = RemoveRedundantNullChecks(sqlBinaryExpression.Right, outerColumnExpressions); + if (sqlBinaryExpression.OperatorType == ExpressionType.AndAlso) + { + var leftPredicate = Rewrite(sqlBinaryExpression.Left, outerColumnExpressions, keepNullableKeyChecks); + var rightPredicate = Rewrite(sqlBinaryExpression.Right, outerColumnExpressions, keepNullableKeyChecks); - return CombineNonNullExpressions(leftPredicate, rightPredicate); + return CombineNonNullExpressions(leftPredicate, rightPredicate); + } } + + return predicate; } - return predicate; + // Counts the non-null-check conjuncts in the extracted join predicate; when more than one remains the resulting join + // predicate is a conjunction subject to C# null semantics expansion. + static int CountNonNullCheckConjuncts(SqlExpression predicate, List outerColumnExpressions) + { + if (predicate is SqlBinaryExpression { OperatorType: ExpressionType.AndAlso } andAlso) + { + return CountNonNullCheckConjuncts(andAlso.Left, outerColumnExpressions) + + CountNonNullCheckConjuncts(andAlso.Right, outerColumnExpressions); + } + + return predicate is SqlBinaryExpression + { + OperatorType: ExpressionType.NotEqual, Right: SqlConstantExpression { Value: null } + } nullCheck + && outerColumnExpressions.Contains(nullCheck.Left) + ? 0 + : 1; + } } } } diff --git a/test/EFCore.Specification.Tests/Query/AdHocNavigationsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/AdHocNavigationsQueryTestBase.cs index 39df84968ff..bd0795080db 100644 --- a/test/EFCore.Specification.Tests/Query/AdHocNavigationsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/AdHocNavigationsQueryTestBase.cs @@ -1650,4 +1650,83 @@ public class Book } #endregion + + #region 35706 + + [Theory, MemberData(nameof(IsAsyncData))] + public virtual async Task Filtered_collection_through_optional_navigation_does_not_match_on_null_keys(bool async) + { + var contextFactory = await InitializeNonSharedTest(seed: c => c.SeedAsync()); + using var context = contextFactory.CreateDbContext(); + + var query = context.People + .OrderBy(p => p.PersonId) + .Select( + subject => new + { + subject.Name, + Coworkers = subject.Employer.Employees + .Where(employee => employee != subject) + .Select(coworker => new { coworker.Name }) + .ToList() + }); + + var people = async + ? await query.ToListAsync() + : query.ToList(); + + var satya = people.Single(p => p.Name == "Satya"); + Assert.Equal(2, satya.Coworkers.Count); + Assert.Contains(satya.Coworkers, c => c.Name == "Brad"); + Assert.Contains(satya.Coworkers, c => c.Name == "Amy"); + + var donald = people.Single(p => p.Name == "Donald"); + Assert.Empty(donald.Coworkers); + } + + protected class Context35706(DbContextOptions options) : DbContext(options) + { + public DbSet Employers { get; set; } + public DbSet People { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasKey(e => e.EmployerId); + modelBuilder.Entity().HasKey(p => p.PersonId); + modelBuilder.Entity() + .HasMany(e => e.Employees) + .WithOne(p => p.Employer) + .HasForeignKey(p => p.EmployerId); + } + + public Task SeedAsync() + { + var microsoft = new Employer35706 { Name = "Microsoft" }; + AddRange( + new Person35706 { Name = "Satya", Employer = microsoft }, + new Person35706 { Name = "Brad", Employer = microsoft }, + new Person35706 { Name = "Amy", Employer = microsoft }, + new Person35706 { Name = "Donald" }, + new Person35706 { Name = "Elon" }); + + return SaveChangesAsync(); + } + + public class Employer35706 + { + public int EmployerId { get; set; } + public string Name { get; set; } + public IList Employees { get; set; } + } + + public class Person35706 + { + public int PersonId { get; set; } + public string Name { get; set; } + public int? EmployerId { get; set; } + public Employer35706 Employer { get; set; } + } + } + + #endregion } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/AdHocNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocNavigationsQuerySqlServerTest.cs index a31fc8d4ecd..0a42d17bbf3 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/AdHocNavigationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocNavigationsQuerySqlServerTest.cs @@ -672,6 +672,20 @@ SELECT COUNT(*) FROM [Books] AS [b] WHERE [a].[AuthorId] = [b].[AuthorId]) AS [BooksCount] FROM [Authors] AS [a] +"""); + } + + public override async Task Filtered_collection_through_optional_navigation_does_not_match_on_null_keys(bool async) + { + await base.Filtered_collection_through_optional_navigation_does_not_match_on_null_keys(async); + + AssertSql( + """ +SELECT [p].[Name], [p].[PersonId], [p0].[Name], [p0].[PersonId] +FROM [People] AS [p] +LEFT JOIN [Employers] AS [e] ON [p].[EmployerId] = [e].[EmployerId] +LEFT JOIN [People] AS [p0] ON [e].[EmployerId] IS NOT NULL AND [e].[EmployerId] = [p0].[EmployerId] AND [p].[PersonId] <> [p0].[PersonId] +ORDER BY [p].[PersonId] """); } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index 988cd20495c..d176266fae1 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -3148,7 +3148,7 @@ FROM [LocustLeaders] AS [l] WHERE [l].[Discriminator] = N'LocustCommander' ) AS [l0] ON [f].[CommanderName] = [l0].[Name] LEFT JOIN [Gears] AS [g] ON [l0].[DefeatedByNickname] = [g].[Nickname] AND [l0].[DefeatedBySquadId] = [g].[SquadId] -LEFT JOIN [Gears] AS [g0] ON ([g].[Nickname] = [g0].[LeaderNickname] OR ([g].[Nickname] IS NULL AND [g0].[LeaderNickname] IS NULL)) AND [g].[SquadId] = [g0].[LeaderSquadId] +LEFT JOIN [Gears] AS [g0] ON [g].[Nickname] IS NOT NULL AND [g].[SquadId] IS NOT NULL AND [g].[Nickname] = [g0].[LeaderNickname] AND [g].[SquadId] = [g0].[LeaderSquadId] ORDER BY [f].[Id], [g0].[Nickname] """); } @@ -3167,7 +3167,7 @@ FROM [LocustLeaders] AS [l] WHERE [l].[Discriminator] = N'LocustCommander' ) AS [l0] ON [f].[CommanderName] = [l0].[Name] LEFT JOIN [Gears] AS [g] ON [l0].[DefeatedByNickname] = [g].[Nickname] AND [l0].[DefeatedBySquadId] = [g].[SquadId] -LEFT JOIN [Gears] AS [g0] ON ([g].[Nickname] = [g0].[LeaderNickname] OR ([g].[Nickname] IS NULL AND [g0].[LeaderNickname] IS NULL)) AND [g].[SquadId] = [g0].[LeaderSquadId] +LEFT JOIN [Gears] AS [g0] ON [g].[Nickname] IS NOT NULL AND [g].[SquadId] IS NOT NULL AND [g].[Nickname] = [g0].[LeaderNickname] AND [g].[SquadId] = [g0].[LeaderSquadId] ORDER BY [f].[Id], [g0].[Nickname] """); } @@ -3210,7 +3210,7 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[Discriminator], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank], [c].[Name], [c].[Location], [c].[Nation] FROM [Gears] AS [g0] INNER JOIN [Cities] AS [c] ON [g0].[CityOfBirthName] = [c].[Name] -) AS [s] ON ([g].[Nickname] = [s].[LeaderNickname] OR ([g].[Nickname] IS NULL AND [s].[LeaderNickname] IS NULL)) AND [g].[SquadId] = [s].[LeaderSquadId] +) AS [s] ON [g].[Nickname] IS NOT NULL AND [g].[SquadId] IS NOT NULL AND [g].[Nickname] = [s].[LeaderNickname] AND [g].[SquadId] = [s].[LeaderSquadId] ORDER BY [l].[Name], [s].[Nickname] """); } @@ -3332,7 +3332,7 @@ FROM [LocustLeaders] AS [l] WHERE [l].[Discriminator] = N'LocustCommander' ) AS [l0] ON [f].[CommanderName] = [l0].[Name] LEFT JOIN [Gears] AS [g] ON [l0].[DefeatedByNickname] = [g].[Nickname] AND [l0].[DefeatedBySquadId] = [g].[SquadId] -LEFT JOIN [Gears] AS [g0] ON ([g].[Nickname] = [g0].[LeaderNickname] OR ([g].[Nickname] IS NULL AND [g0].[LeaderNickname] IS NULL)) AND [g].[SquadId] = [g0].[LeaderSquadId] +LEFT JOIN [Gears] AS [g0] ON [g].[Nickname] IS NOT NULL AND [g].[SquadId] IS NOT NULL AND [g].[Nickname] = [g0].[LeaderNickname] AND [g].[SquadId] = [g0].[LeaderSquadId] ORDER BY [f].[Id], [g0].[Nickname] """); } @@ -3385,7 +3385,7 @@ FROM [LocustLeaders] AS [l] WHERE [l].[Discriminator] = N'LocustCommander' ) AS [l0] ON [f].[CommanderName] = [l0].[Name] LEFT JOIN [Gears] AS [g] ON [l0].[DefeatedByNickname] = [g].[Nickname] AND [l0].[DefeatedBySquadId] = [g].[SquadId] -LEFT JOIN [Gears] AS [g0] ON ([g].[Nickname] = [g0].[LeaderNickname] OR ([g].[Nickname] IS NULL AND [g0].[LeaderNickname] IS NULL)) AND [g].[SquadId] = [g0].[LeaderSquadId] +LEFT JOIN [Gears] AS [g0] ON [g].[Nickname] IS NOT NULL AND [g].[SquadId] IS NOT NULL AND [g].[Nickname] = [g0].[LeaderNickname] AND [g].[SquadId] = [g0].[LeaderSquadId] ORDER BY [f].[Id], [g0].[Nickname] """); } @@ -4292,7 +4292,7 @@ LEFT JOIN ( FROM [Gears] AS [g] WHERE [g].[Discriminator] = N'Officer' ) AS [g0] ON [t].[GearNickName] = [g0].[Nickname] -LEFT JOIN [Gears] AS [g1] ON ([g0].[Nickname] = [g1].[LeaderNickname] OR ([g0].[Nickname] IS NULL AND [g1].[LeaderNickname] IS NULL)) AND [g0].[SquadId] = [g1].[LeaderSquadId] +LEFT JOIN [Gears] AS [g1] ON [g0].[Nickname] IS NOT NULL AND [g0].[SquadId] IS NOT NULL AND [g0].[Nickname] = [g1].[LeaderNickname] AND [g0].[SquadId] = [g1].[LeaderSquadId] ORDER BY [t].[Id], [g0].[Nickname], [g0].[SquadId], [g1].[Nickname] """); } @@ -6185,7 +6185,7 @@ LEFT JOIN ( FROM [Gears] AS [g0] ) AS [g1] WHERE [g1].[row] <= 50 -) AS [g2] ON ([g].[Nickname] = [g2].[LeaderNickname] OR ([g].[Nickname] IS NULL AND [g2].[LeaderNickname] IS NULL)) AND [g].[SquadId] = [g2].[LeaderSquadId] +) AS [g2] ON [g].[Nickname] IS NOT NULL AND [g].[SquadId] IS NOT NULL AND [g].[Nickname] = [g2].[LeaderNickname] AND [g].[SquadId] = [g2].[LeaderSquadId] WHERE [g].[Discriminator] = N'Officer' ORDER BY [t].[Id], [g2].[Nickname] """); @@ -6200,7 +6200,7 @@ public override async Task Project_collection_navigation_nested_composite_key(bo SELECT [t].[Id], [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[Discriminator], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank] FROM [Tags] AS [t] LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] -LEFT JOIN [Gears] AS [g0] ON ([g].[Nickname] = [g0].[LeaderNickname] OR ([g].[Nickname] IS NULL AND [g0].[LeaderNickname] IS NULL)) AND [g].[SquadId] = [g0].[LeaderSquadId] +LEFT JOIN [Gears] AS [g0] ON [g].[Nickname] IS NOT NULL AND [g].[SquadId] IS NOT NULL AND [g].[Nickname] = [g0].[LeaderNickname] AND [g].[SquadId] = [g0].[LeaderSquadId] WHERE [g].[Discriminator] = N'Officer' ORDER BY [t].[Id], [g0].[Nickname] """); @@ -6214,7 +6214,7 @@ public override async Task Null_checks_in_correlated_predicate_are_correctly_tra """ SELECT [t].[Id], [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Tags] AS [t] -LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] AND [t].[Note] IS NOT NULL +LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] IS NOT NULL AND [t].[GearSquadId] = [g].[SquadId] AND [t].[GearNickName] IS NOT NULL AND [t].[Note] IS NOT NULL ORDER BY [t].[Id], [g].[Nickname] """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Inheritance/TPCGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Inheritance/TPCGearsOfWarQuerySqlServerTest.cs index 815059c8ac5..b5c826cd562 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/Inheritance/TPCGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/Inheritance/TPCGearsOfWarQuerySqlServerTest.cs @@ -4187,7 +4187,7 @@ FROM [Gears] AS [g0] UNION ALL SELECT [o0].[Nickname], [o0].[SquadId], [o0].[AssignedCityName], [o0].[CityOfBirthName], [o0].[FullName], [o0].[HasSoulPatch], [o0].[LeaderNickname], [o0].[LeaderSquadId], [o0].[Rank], N'Officer' AS [Discriminator] FROM [Officers] AS [o0] -) AS [u0] ON ([u].[Nickname] = [u0].[LeaderNickname] OR ([u].[Nickname] IS NULL AND [u0].[LeaderNickname] IS NULL)) AND [u].[SquadId] = [u0].[LeaderSquadId] +) AS [u0] ON [u].[Nickname] IS NOT NULL AND [u].[SquadId] IS NOT NULL AND [u].[Nickname] = [u0].[LeaderNickname] AND [u].[SquadId] = [u0].[LeaderSquadId] ORDER BY [l].[Id], [u0].[Nickname] """); } @@ -4214,7 +4214,7 @@ FROM [Gears] AS [g0] UNION ALL SELECT [o0].[Nickname], [o0].[SquadId], [o0].[AssignedCityName], [o0].[CityOfBirthName], [o0].[FullName], [o0].[HasSoulPatch], [o0].[LeaderNickname], [o0].[LeaderSquadId], [o0].[Rank], N'Officer' AS [Discriminator] FROM [Officers] AS [o0] -) AS [u0] ON ([u].[Nickname] = [u0].[LeaderNickname] OR ([u].[Nickname] IS NULL AND [u0].[LeaderNickname] IS NULL)) AND [u].[SquadId] = [u0].[LeaderSquadId] +) AS [u0] ON [u].[Nickname] IS NOT NULL AND [u].[SquadId] IS NOT NULL AND [u].[Nickname] = [u0].[LeaderNickname] AND [u].[SquadId] = [u0].[LeaderSquadId] ORDER BY [l].[Id], [u0].[Nickname] """); } @@ -4299,7 +4299,7 @@ UNION ALL FROM [Officers] AS [o0] ) AS [u1] INNER JOIN [Cities] AS [c] ON [u1].[CityOfBirthName] = [c].[Name] -) AS [s] ON ([u0].[Nickname] = [s].[LeaderNickname] OR ([u0].[Nickname] IS NULL AND [s].[LeaderNickname] IS NULL)) AND [u0].[SquadId] = [s].[LeaderSquadId] +) AS [s] ON [u0].[Nickname] IS NOT NULL AND [u0].[SquadId] IS NOT NULL AND [u0].[Nickname] = [s].[LeaderNickname] AND [u0].[SquadId] = [s].[LeaderSquadId] ORDER BY [u].[Name], [s].[Nickname] """); } @@ -4513,7 +4513,7 @@ FROM [Gears] AS [g0] UNION ALL SELECT [o0].[Nickname], [o0].[SquadId], [o0].[AssignedCityName], [o0].[CityOfBirthName], [o0].[FullName], [o0].[HasSoulPatch], [o0].[LeaderNickname], [o0].[LeaderSquadId], [o0].[Rank], N'Officer' AS [Discriminator] FROM [Officers] AS [o0] -) AS [u0] ON ([u].[Nickname] = [u0].[LeaderNickname] OR ([u].[Nickname] IS NULL AND [u0].[LeaderNickname] IS NULL)) AND [u].[SquadId] = [u0].[LeaderSquadId] +) AS [u0] ON [u].[Nickname] IS NOT NULL AND [u].[SquadId] IS NOT NULL AND [u].[Nickname] = [u0].[LeaderNickname] AND [u].[SquadId] = [u0].[LeaderSquadId] ORDER BY [l].[Id], [u0].[Nickname] """); } @@ -4604,7 +4604,7 @@ FROM [Gears] AS [g0] UNION ALL SELECT [o0].[Nickname], [o0].[SquadId], [o0].[AssignedCityName], [o0].[CityOfBirthName], [o0].[FullName], [o0].[HasSoulPatch], [o0].[LeaderNickname], [o0].[LeaderSquadId], [o0].[Rank], N'Officer' AS [Discriminator] FROM [Officers] AS [o0] -) AS [u0] ON ([u].[Nickname] = [u0].[LeaderNickname] OR ([u].[Nickname] IS NULL AND [u0].[LeaderNickname] IS NULL)) AND [u].[SquadId] = [u0].[LeaderSquadId] +) AS [u0] ON [u].[Nickname] IS NOT NULL AND [u].[SquadId] IS NOT NULL AND [u].[Nickname] = [u0].[LeaderNickname] AND [u].[SquadId] = [u0].[LeaderSquadId] ORDER BY [l].[Id], [u0].[Nickname] """); } @@ -5787,7 +5787,7 @@ FROM [Gears] AS [g] UNION ALL SELECT [o0].[Nickname], [o0].[SquadId], [o0].[FullName], [o0].[LeaderNickname], [o0].[LeaderSquadId] FROM [Officers] AS [o0] -) AS [u0] ON ([u].[Nickname] = [u0].[LeaderNickname] OR ([u].[Nickname] IS NULL AND [u0].[LeaderNickname] IS NULL)) AND [u].[SquadId] = [u0].[LeaderSquadId] +) AS [u0] ON [u].[Nickname] IS NOT NULL AND [u].[SquadId] IS NOT NULL AND [u].[Nickname] = [u0].[LeaderNickname] AND [u].[SquadId] = [u0].[LeaderSquadId] ORDER BY [t].[Id], [u].[Nickname], [u].[SquadId], [u0].[Nickname] """); } @@ -8353,7 +8353,7 @@ FROM [Officers] AS [o0] ) AS [u0] ) AS [u1] WHERE [u1].[row] <= 50 -) AS [u2] ON ([u].[Nickname] = [u2].[LeaderNickname] OR ([u].[Nickname] IS NULL AND [u2].[LeaderNickname] IS NULL)) AND [u].[SquadId] = [u2].[LeaderSquadId] +) AS [u2] ON [u].[Nickname] IS NOT NULL AND [u].[SquadId] IS NOT NULL AND [u].[Nickname] = [u2].[LeaderNickname] AND [u].[SquadId] = [u2].[LeaderSquadId] WHERE [u].[Discriminator] = N'Officer' ORDER BY [t].[Id], [u2].[Nickname] """); @@ -8380,7 +8380,7 @@ FROM [Gears] AS [g0] UNION ALL SELECT [o0].[Nickname], [o0].[SquadId], [o0].[AssignedCityName], [o0].[CityOfBirthName], [o0].[FullName], [o0].[HasSoulPatch], [o0].[LeaderNickname], [o0].[LeaderSquadId], [o0].[Rank], N'Officer' AS [Discriminator] FROM [Officers] AS [o0] -) AS [u0] ON ([u].[Nickname] = [u0].[LeaderNickname] OR ([u].[Nickname] IS NULL AND [u0].[LeaderNickname] IS NULL)) AND [u].[SquadId] = [u0].[LeaderSquadId] +) AS [u0] ON [u].[Nickname] IS NOT NULL AND [u].[SquadId] IS NOT NULL AND [u].[Nickname] = [u0].[LeaderNickname] AND [u].[SquadId] = [u0].[LeaderSquadId] WHERE [u].[Discriminator] = N'Officer' ORDER BY [t].[Id], [u0].[Nickname] """); @@ -8400,7 +8400,7 @@ FROM [Gears] AS [g] UNION ALL SELECT [o].[Nickname], [o].[SquadId], [o].[AssignedCityName], [o].[CityOfBirthName], [o].[FullName], [o].[HasSoulPatch], [o].[LeaderNickname], [o].[LeaderSquadId], [o].[Rank], N'Officer' AS [Discriminator] FROM [Officers] AS [o] -) AS [u] ON [t].[GearNickName] = [u].[Nickname] AND [t].[GearSquadId] = [u].[SquadId] AND [t].[Note] IS NOT NULL +) AS [u] ON [t].[GearNickName] = [u].[Nickname] AND [t].[GearSquadId] IS NOT NULL AND [t].[GearSquadId] = [u].[SquadId] AND [t].[GearNickName] IS NOT NULL AND [t].[Note] IS NOT NULL ORDER BY [t].[Id], [u].[Nickname] """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Inheritance/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Inheritance/TPTGearsOfWarQuerySqlServerTest.cs index 0c01cd8c145..63497512cd4 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/Inheritance/TPTGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/Inheritance/TPTGearsOfWarQuerySqlServerTest.cs @@ -3632,7 +3632,7 @@ WHEN [o].[Nickname] IS NOT NULL THEN N'Officer' END AS [Discriminator] FROM [Gears] AS [g0] LEFT JOIN [Officers] AS [o] ON [g0].[Nickname] = [o].[Nickname] AND [g0].[SquadId] = [o].[SquadId] -) AS [s1] ON ([s0].[Nickname] = [s1].[LeaderNickname] OR ([s0].[Nickname] IS NULL AND [s1].[LeaderNickname] IS NULL)) AND [s0].[SquadId] = [s1].[LeaderSquadId] +) AS [s1] ON [s0].[Nickname] IS NOT NULL AND [s0].[SquadId] IS NOT NULL AND [s0].[Nickname] = [s1].[LeaderNickname] AND [s0].[SquadId] = [s1].[LeaderSquadId] WHERE [l].[Id] IS NOT NULL ORDER BY [f].[Id], [s1].[Nickname] """); @@ -3662,7 +3662,7 @@ WHEN [o].[Nickname] IS NOT NULL THEN N'Officer' END AS [Discriminator] FROM [Gears] AS [g0] LEFT JOIN [Officers] AS [o] ON [g0].[Nickname] = [o].[Nickname] AND [g0].[SquadId] = [o].[SquadId] -) AS [s1] ON ([s0].[Nickname] = [s1].[LeaderNickname] OR ([s0].[Nickname] IS NULL AND [s1].[LeaderNickname] IS NULL)) AND [s0].[SquadId] = [s1].[LeaderSquadId] +) AS [s1] ON [s0].[Nickname] IS NOT NULL AND [s0].[SquadId] IS NOT NULL AND [s0].[Nickname] = [s1].[LeaderNickname] AND [s0].[SquadId] = [s1].[LeaderSquadId] WHERE [l].[Id] IS NOT NULL ORDER BY [f].[Id], [s1].[Nickname] """); @@ -3736,7 +3736,7 @@ WHEN [o0].[Nickname] IS NOT NULL THEN N'Officer' FROM [Gears] AS [g0] LEFT JOIN [Officers] AS [o0] ON [g0].[Nickname] = [o0].[Nickname] AND [g0].[SquadId] = [o0].[SquadId] INNER JOIN [Cities] AS [c] ON [g0].[CityOfBirthName] = [c].[Name] -) AS [s0] ON ([s].[Nickname] = [s0].[LeaderNickname] OR ([s].[Nickname] IS NULL AND [s0].[LeaderNickname] IS NULL)) AND [s].[SquadId] = [s0].[LeaderSquadId] +) AS [s0] ON [s].[Nickname] IS NOT NULL AND [s].[SquadId] IS NOT NULL AND [s].[Nickname] = [s0].[LeaderNickname] AND [s].[SquadId] = [s0].[LeaderSquadId] ORDER BY [l].[Name], [s0].[Nickname] """); } @@ -3936,7 +3936,7 @@ WHEN [o0].[Nickname] IS NOT NULL THEN N'Officer' END AS [Discriminator] FROM [Gears] AS [g0] LEFT JOIN [Officers] AS [o0] ON [g0].[Nickname] = [o0].[Nickname] AND [g0].[SquadId] = [o0].[SquadId] -) AS [s1] ON ([s0].[Nickname] = [s1].[LeaderNickname] OR ([s0].[Nickname] IS NULL AND [s1].[LeaderNickname] IS NULL)) AND [s0].[SquadId] = [s1].[LeaderSquadId] +) AS [s1] ON [s0].[Nickname] IS NOT NULL AND [s0].[SquadId] IS NOT NULL AND [s0].[Nickname] = [s1].[LeaderNickname] AND [s0].[SquadId] = [s1].[LeaderSquadId] ORDER BY [f].[Id], [s1].[Nickname] """); } @@ -4028,7 +4028,7 @@ WHEN [o0].[Nickname] IS NOT NULL THEN N'Officer' END AS [Discriminator] FROM [Gears] AS [g0] LEFT JOIN [Officers] AS [o0] ON [g0].[Nickname] = [o0].[Nickname] AND [g0].[SquadId] = [o0].[SquadId] -) AS [s1] ON ([s0].[Nickname] = [s1].[LeaderNickname] OR ([s0].[Nickname] IS NULL AND [s1].[LeaderNickname] IS NULL)) AND [s0].[SquadId] = [s1].[LeaderSquadId] +) AS [s1] ON [s0].[Nickname] IS NOT NULL AND [s0].[SquadId] IS NOT NULL AND [s0].[Nickname] = [s1].[LeaderNickname] AND [s0].[SquadId] = [s1].[LeaderSquadId] ORDER BY [f].[Id], [s1].[Nickname] """); } @@ -4955,7 +4955,7 @@ WHERE [o].[Nickname] IS NOT NULL LEFT JOIN ( SELECT [g0].[FullName], [g0].[Nickname], [g0].[SquadId], [g0].[LeaderNickname], [g0].[LeaderSquadId] FROM [Gears] AS [g0] -) AS [s0] ON ([s].[Nickname] = [s0].[LeaderNickname] OR ([s].[Nickname] IS NULL AND [s0].[LeaderNickname] IS NULL)) AND [s].[SquadId] = [s0].[LeaderSquadId] +) AS [s0] ON [s].[Nickname] IS NOT NULL AND [s].[SquadId] IS NOT NULL AND [s].[Nickname] = [s0].[LeaderNickname] AND [s].[SquadId] = [s0].[LeaderSquadId] ORDER BY [t].[Id], [s].[Nickname], [s].[SquadId], [s0].[Nickname] """); } @@ -7057,7 +7057,7 @@ FROM [Gears] AS [g0] LEFT JOIN [Officers] AS [o0] ON [g0].[Nickname] = [o0].[Nickname] AND [g0].[SquadId] = [o0].[SquadId] ) AS [s0] WHERE [s0].[row] <= 50 -) AS [s1] ON ([s].[Nickname] = [s1].[LeaderNickname] OR ([s].[Nickname] IS NULL AND [s1].[LeaderNickname] IS NULL)) AND [s].[SquadId] = [s1].[LeaderSquadId] +) AS [s1] ON [s].[Nickname] IS NOT NULL AND [s].[SquadId] IS NOT NULL AND [s].[Nickname] = [s1].[LeaderNickname] AND [s].[SquadId] = [s1].[LeaderSquadId] WHERE [s].[Discriminator] = N'Officer' ORDER BY [t].[Id], [s1].[Nickname] """); @@ -7084,7 +7084,7 @@ WHEN [o0].[Nickname] IS NOT NULL THEN N'Officer' END AS [Discriminator] FROM [Gears] AS [g0] LEFT JOIN [Officers] AS [o0] ON [g0].[Nickname] = [o0].[Nickname] AND [g0].[SquadId] = [o0].[SquadId] -) AS [s0] ON ([s].[Nickname] = [s0].[LeaderNickname] OR ([s].[Nickname] IS NULL AND [s0].[LeaderNickname] IS NULL)) AND [s].[SquadId] = [s0].[LeaderSquadId] +) AS [s0] ON [s].[Nickname] IS NOT NULL AND [s].[SquadId] IS NOT NULL AND [s].[Nickname] = [s0].[LeaderNickname] AND [s].[SquadId] = [s0].[LeaderSquadId] WHERE [s].[Discriminator] = N'Officer' ORDER BY [t].[Id], [s0].[Nickname] """); @@ -7104,7 +7104,7 @@ WHEN [o].[Nickname] IS NOT NULL THEN N'Officer' END AS [Discriminator] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId] -) AS [s] ON [t].[GearNickName] = [s].[Nickname] AND [t].[GearSquadId] = [s].[SquadId] AND [t].[Note] IS NOT NULL +) AS [s] ON [t].[GearNickName] = [s].[Nickname] AND [t].[GearSquadId] IS NOT NULL AND [t].[GearSquadId] = [s].[SquadId] AND [t].[GearNickName] IS NOT NULL AND [t].[Note] IS NOT NULL ORDER BY [t].[Id], [s].[Nickname] """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs index 2e208818c4a..f39a09707b6 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs @@ -1930,7 +1930,7 @@ public override async Task Project_collection_navigation_nested_composite_key(bo SELECT [t].[Id], [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[Discriminator], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[PeriodEnd], [g0].[PeriodStart], [g0].[Rank] FROM [Tags] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [t] LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] -LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0] ON ([g].[Nickname] = [g0].[LeaderNickname] OR ([g].[Nickname] IS NULL AND [g0].[LeaderNickname] IS NULL)) AND [g].[SquadId] = [g0].[LeaderSquadId] +LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0] ON [g].[Nickname] IS NOT NULL AND [g].[SquadId] IS NOT NULL AND [g].[Nickname] = [g0].[LeaderNickname] AND [g].[SquadId] = [g0].[LeaderSquadId] WHERE [g].[Discriminator] = N'Officer' ORDER BY [t].[Id], [g0].[Nickname] """); @@ -3368,7 +3368,7 @@ LEFT JOIN ( FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0] ) AS [g1] WHERE [g1].[row] <= 50 -) AS [g2] ON ([g].[Nickname] = [g2].[LeaderNickname] OR ([g].[Nickname] IS NULL AND [g2].[LeaderNickname] IS NULL)) AND [g].[SquadId] = [g2].[LeaderSquadId] +) AS [g2] ON [g].[Nickname] IS NOT NULL AND [g].[SquadId] IS NOT NULL AND [g].[Nickname] = [g2].[LeaderNickname] AND [g].[SquadId] = [g2].[LeaderSquadId] WHERE [g].[Discriminator] = N'Officer' ORDER BY [t].[Id], [g2].[Nickname] """); @@ -3940,7 +3940,7 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[Discriminator], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[PeriodEnd], [g0].[PeriodStart], [g0].[Rank], [c].[Name], [c].[Location], [c].[Nation], [c].[PeriodEnd] AS [PeriodEnd0], [c].[PeriodStart] AS [PeriodStart0] FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0] INNER JOIN [Cities] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [c] ON [g0].[CityOfBirthName] = [c].[Name] -) AS [s] ON ([g].[Nickname] = [s].[LeaderNickname] OR ([g].[Nickname] IS NULL AND [s].[LeaderNickname] IS NULL)) AND [g].[SquadId] = [s].[LeaderSquadId] +) AS [s] ON [g].[Nickname] IS NOT NULL AND [g].[SquadId] IS NOT NULL AND [g].[Nickname] = [s].[LeaderNickname] AND [g].[SquadId] = [s].[LeaderSquadId] ORDER BY [l].[Name], [s].[Nickname] """); } @@ -4810,7 +4810,7 @@ LEFT JOIN ( WHERE [l].[Discriminator] = N'LocustCommander' ) AS [l0] ON [f].[CommanderName] = [l0].[Name] LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [l0].[DefeatedByNickname] = [g].[Nickname] AND [l0].[DefeatedBySquadId] = [g].[SquadId] -LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0] ON ([g].[Nickname] = [g0].[LeaderNickname] OR ([g].[Nickname] IS NULL AND [g0].[LeaderNickname] IS NULL)) AND [g].[SquadId] = [g0].[LeaderSquadId] +LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0] ON [g].[Nickname] IS NOT NULL AND [g].[SquadId] IS NOT NULL AND [g].[Nickname] = [g0].[LeaderNickname] AND [g].[SquadId] = [g0].[LeaderSquadId] ORDER BY [f].[Id], [g0].[Nickname] """); } @@ -5052,7 +5052,7 @@ LEFT JOIN ( WHERE [l].[Discriminator] = N'LocustCommander' ) AS [l0] ON [f].[CommanderName] = [l0].[Name] LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [l0].[DefeatedByNickname] = [g].[Nickname] AND [l0].[DefeatedBySquadId] = [g].[SquadId] -LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0] ON ([g].[Nickname] = [g0].[LeaderNickname] OR ([g].[Nickname] IS NULL AND [g0].[LeaderNickname] IS NULL)) AND [g].[SquadId] = [g0].[LeaderSquadId] +LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0] ON [g].[Nickname] IS NOT NULL AND [g].[SquadId] IS NOT NULL AND [g].[Nickname] = [g0].[LeaderNickname] AND [g].[SquadId] = [g0].[LeaderSquadId] ORDER BY [f].[Id], [g0].[Nickname] """); } @@ -6597,7 +6597,7 @@ LEFT JOIN ( WHERE [l].[Discriminator] = N'LocustCommander' ) AS [l0] ON [f].[CommanderName] = [l0].[Name] LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [l0].[DefeatedByNickname] = [g].[Nickname] AND [l0].[DefeatedBySquadId] = [g].[SquadId] -LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0] ON ([g].[Nickname] = [g0].[LeaderNickname] OR ([g].[Nickname] IS NULL AND [g0].[LeaderNickname] IS NULL)) AND [g].[SquadId] = [g0].[LeaderSquadId] +LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0] ON [g].[Nickname] IS NOT NULL AND [g].[SquadId] IS NOT NULL AND [g].[Nickname] = [g0].[LeaderNickname] AND [g].[SquadId] = [g0].[LeaderSquadId] ORDER BY [f].[Id], [g0].[Nickname] """); } @@ -6849,7 +6849,7 @@ LEFT JOIN ( WHERE [l].[Discriminator] = N'LocustCommander' ) AS [l0] ON [f].[CommanderName] = [l0].[Name] LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [l0].[DefeatedByNickname] = [g].[Nickname] AND [l0].[DefeatedBySquadId] = [g].[SquadId] -LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0] ON ([g].[Nickname] = [g0].[LeaderNickname] OR ([g].[Nickname] IS NULL AND [g0].[LeaderNickname] IS NULL)) AND [g].[SquadId] = [g0].[LeaderSquadId] +LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0] ON [g].[Nickname] IS NOT NULL AND [g].[SquadId] IS NOT NULL AND [g].[Nickname] = [g0].[LeaderNickname] AND [g].[SquadId] = [g0].[LeaderSquadId] ORDER BY [f].[Id], [g0].[Nickname] """); } @@ -7785,7 +7785,7 @@ public override async Task Null_checks_in_correlated_predicate_are_correctly_tra """ SELECT [t].[Id], [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[PeriodEnd], [g].[PeriodStart], [g].[Rank] FROM [Tags] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [t] -LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] AND [t].[Note] IS NOT NULL +LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] IS NOT NULL AND [t].[GearSquadId] = [g].[SquadId] AND [t].[GearNickName] IS NOT NULL AND [t].[Note] IS NOT NULL ORDER BY [t].[Id], [g].[Nickname] """); } @@ -8293,7 +8293,7 @@ LEFT JOIN ( FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] WHERE [g].[Discriminator] = N'Officer' ) AS [g0] ON [t].[GearNickName] = [g0].[Nickname] -LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g1] ON ([g0].[Nickname] = [g1].[LeaderNickname] OR ([g0].[Nickname] IS NULL AND [g1].[LeaderNickname] IS NULL)) AND [g0].[SquadId] = [g1].[LeaderSquadId] +LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g1] ON [g0].[Nickname] IS NOT NULL AND [g0].[SquadId] IS NOT NULL AND [g0].[Nickname] = [g1].[LeaderNickname] AND [g0].[SquadId] = [g1].[LeaderSquadId] ORDER BY [t].[Id], [g0].[Nickname], [g0].[SquadId], [g1].[Nickname] """); } diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/AdHocNavigationsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/AdHocNavigationsQuerySqliteTest.cs index 81e7488cbe6..173e277f20c 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/AdHocNavigationsQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/AdHocNavigationsQuerySqliteTest.cs @@ -81,6 +81,20 @@ public override async Task Consecutive_selects_with_conditional_projection_neste LEFT JOIN "Address" AS "a" ON "j"."AddressId" = "a"."Id" WHERE "u"."Id" = 1 LIMIT 1 +"""); + } + + public override async Task Filtered_collection_through_optional_navigation_does_not_match_on_null_keys(bool async) + { + await base.Filtered_collection_through_optional_navigation_does_not_match_on_null_keys(async); + + AssertSql( + """ +SELECT "p"."Name", "p"."PersonId", "p0"."Name", "p0"."PersonId" +FROM "People" AS "p" +LEFT JOIN "Employers" AS "e" ON "p"."EmployerId" = "e"."EmployerId" +LEFT JOIN "People" AS "p0" ON "e"."EmployerId" IS NOT NULL AND "e"."EmployerId" = "p0"."EmployerId" AND "p"."PersonId" <> "p0"."PersonId" +ORDER BY "p"."PersonId" """); } } diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs index 0d1e8e24a82..c590930011d 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs @@ -2705,7 +2705,7 @@ LEFT JOIN ( FROM "Gears" AS "g0" ) AS "g1" WHERE "g1"."row" <= 50 -) AS "g2" ON ("g"."Nickname" = "g2"."LeaderNickname" OR ("g"."Nickname" IS NULL AND "g2"."LeaderNickname" IS NULL)) AND "g"."SquadId" = "g2"."LeaderSquadId" +) AS "g2" ON "g"."Nickname" IS NOT NULL AND "g"."SquadId" IS NOT NULL AND "g"."Nickname" = "g2"."LeaderNickname" AND "g"."SquadId" = "g2"."LeaderSquadId" WHERE "g"."Discriminator" = 'Officer' ORDER BY "t"."Id", "g2"."Nickname" """); @@ -3923,7 +3923,7 @@ LEFT JOIN ( SELECT "g0"."Nickname", "g0"."SquadId", "g0"."AssignedCityName", "g0"."CityOfBirthName", "g0"."Discriminator", "g0"."FullName", "g0"."HasSoulPatch", "g0"."LeaderNickname", "g0"."LeaderSquadId", "g0"."Rank", "c"."Name", "c"."Location", "c"."Nation" FROM "Gears" AS "g0" INNER JOIN "Cities" AS "c" ON "g0"."CityOfBirthName" = "c"."Name" -) AS "s" ON ("g"."Nickname" = "s"."LeaderNickname" OR ("g"."Nickname" IS NULL AND "s"."LeaderNickname" IS NULL)) AND "g"."SquadId" = "s"."LeaderSquadId" +) AS "s" ON "g"."Nickname" IS NOT NULL AND "g"."SquadId" IS NOT NULL AND "g"."Nickname" = "s"."LeaderNickname" AND "g"."SquadId" = "s"."LeaderSquadId" ORDER BY "l"."Name", "s"."Nickname" """); } @@ -4824,7 +4824,7 @@ public override async Task Project_collection_navigation_nested_composite_key(bo SELECT "t"."Id", "g0"."Nickname", "g0"."SquadId", "g0"."AssignedCityName", "g0"."CityOfBirthName", "g0"."Discriminator", "g0"."FullName", "g0"."HasSoulPatch", "g0"."LeaderNickname", "g0"."LeaderSquadId", "g0"."Rank" FROM "Tags" AS "t" LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId" -LEFT JOIN "Gears" AS "g0" ON ("g"."Nickname" = "g0"."LeaderNickname" OR ("g"."Nickname" IS NULL AND "g0"."LeaderNickname" IS NULL)) AND "g"."SquadId" = "g0"."LeaderSquadId" +LEFT JOIN "Gears" AS "g0" ON "g"."Nickname" IS NOT NULL AND "g"."SquadId" IS NOT NULL AND "g"."Nickname" = "g0"."LeaderNickname" AND "g"."SquadId" = "g0"."LeaderSquadId" WHERE "g"."Discriminator" = 'Officer' ORDER BY "t"."Id", "g0"."Nickname" """); @@ -4849,7 +4849,7 @@ public override async Task Null_checks_in_correlated_predicate_are_correctly_tra """ SELECT "t"."Id", "g"."Nickname", "g"."SquadId", "g"."AssignedCityName", "g"."CityOfBirthName", "g"."Discriminator", "g"."FullName", "g"."HasSoulPatch", "g"."LeaderNickname", "g"."LeaderSquadId", "g"."Rank" FROM "Tags" AS "t" -LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId" AND "t"."Note" IS NOT NULL +LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" IS NOT NULL AND "t"."GearSquadId" = "g"."SquadId" AND "t"."GearNickName" IS NOT NULL AND "t"."Note" IS NOT NULL ORDER BY "t"."Id", "g"."Nickname" """); } @@ -6030,7 +6030,7 @@ LEFT JOIN ( WHERE "l"."Discriminator" = 'LocustCommander' ) AS "l0" ON "f"."CommanderName" = "l0"."Name" LEFT JOIN "Gears" AS "g" ON "l0"."DefeatedByNickname" = "g"."Nickname" AND "l0"."DefeatedBySquadId" = "g"."SquadId" -LEFT JOIN "Gears" AS "g0" ON ("g"."Nickname" = "g0"."LeaderNickname" OR ("g"."Nickname" IS NULL AND "g0"."LeaderNickname" IS NULL)) AND "g"."SquadId" = "g0"."LeaderSquadId" +LEFT JOIN "Gears" AS "g0" ON "g"."Nickname" IS NOT NULL AND "g"."SquadId" IS NOT NULL AND "g"."Nickname" = "g0"."LeaderNickname" AND "g"."SquadId" = "g0"."LeaderSquadId" ORDER BY "f"."Id", "g0"."Nickname" """); } @@ -6437,7 +6437,7 @@ LEFT JOIN ( FROM "Gears" AS "g" WHERE "g"."Discriminator" = 'Officer' ) AS "g0" ON "t"."GearNickName" = "g0"."Nickname" -LEFT JOIN "Gears" AS "g1" ON ("g0"."Nickname" = "g1"."LeaderNickname" OR ("g0"."Nickname" IS NULL AND "g1"."LeaderNickname" IS NULL)) AND "g0"."SquadId" = "g1"."LeaderSquadId" +LEFT JOIN "Gears" AS "g1" ON "g0"."Nickname" IS NOT NULL AND "g0"."SquadId" IS NOT NULL AND "g0"."Nickname" = "g1"."LeaderNickname" AND "g0"."SquadId" = "g1"."LeaderSquadId" ORDER BY "t"."Id", "g0"."Nickname", "g0"."SquadId", "g1"."Nickname" """); } @@ -6729,7 +6729,7 @@ LEFT JOIN ( WHERE "l"."Discriminator" = 'LocustCommander' ) AS "l0" ON "f"."CommanderName" = "l0"."Name" LEFT JOIN "Gears" AS "g" ON "l0"."DefeatedByNickname" = "g"."Nickname" AND "l0"."DefeatedBySquadId" = "g"."SquadId" -LEFT JOIN "Gears" AS "g0" ON ("g"."Nickname" = "g0"."LeaderNickname" OR ("g"."Nickname" IS NULL AND "g0"."LeaderNickname" IS NULL)) AND "g"."SquadId" = "g0"."LeaderSquadId" +LEFT JOIN "Gears" AS "g0" ON "g"."Nickname" IS NOT NULL AND "g"."SquadId" IS NOT NULL AND "g"."Nickname" = "g0"."LeaderNickname" AND "g"."SquadId" = "g0"."LeaderSquadId" ORDER BY "f"."Id", "g0"."Nickname" """); } @@ -7455,7 +7455,7 @@ LEFT JOIN ( WHERE "l"."Discriminator" = 'LocustCommander' ) AS "l0" ON "f"."CommanderName" = "l0"."Name" LEFT JOIN "Gears" AS "g" ON "l0"."DefeatedByNickname" = "g"."Nickname" AND "l0"."DefeatedBySquadId" = "g"."SquadId" -LEFT JOIN "Gears" AS "g0" ON ("g"."Nickname" = "g0"."LeaderNickname" OR ("g"."Nickname" IS NULL AND "g0"."LeaderNickname" IS NULL)) AND "g"."SquadId" = "g0"."LeaderSquadId" +LEFT JOIN "Gears" AS "g0" ON "g"."Nickname" IS NOT NULL AND "g"."SquadId" IS NOT NULL AND "g"."Nickname" = "g0"."LeaderNickname" AND "g"."SquadId" = "g0"."LeaderSquadId" ORDER BY "f"."Id", "g0"."Nickname" """); } @@ -7576,7 +7576,7 @@ LEFT JOIN ( WHERE "l"."Discriminator" = 'LocustCommander' ) AS "l0" ON "f"."CommanderName" = "l0"."Name" LEFT JOIN "Gears" AS "g" ON "l0"."DefeatedByNickname" = "g"."Nickname" AND "l0"."DefeatedBySquadId" = "g"."SquadId" -LEFT JOIN "Gears" AS "g0" ON ("g"."Nickname" = "g0"."LeaderNickname" OR ("g"."Nickname" IS NULL AND "g0"."LeaderNickname" IS NULL)) AND "g"."SquadId" = "g0"."LeaderSquadId" +LEFT JOIN "Gears" AS "g0" ON "g"."Nickname" IS NOT NULL AND "g"."SquadId" IS NOT NULL AND "g"."Nickname" = "g0"."LeaderNickname" AND "g"."SquadId" = "g0"."LeaderSquadId" ORDER BY "f"."Id", "g0"."Nickname" """); }