From 43954b983d7e7294bda21347896c4610060d7381 Mon Sep 17 00:00:00 2001 From: Smit Patel Date: Thu, 31 Oct 2019 18:47:50 -0700 Subject: [PATCH 1/4] Query: Materialize results of FirstOrDefault in subquery only when there are rows Issue: When we generate translation for subquery.FirstOrDefault() using Left join, we get null in values when there is no associated record. Then we try to create result with default values rather than returning default of result type. Fix: Whenever we go through path where we are adding subquery.FirstOrDefault in projection, we inject 1 as dummy column. If we see 1 in result then only we materialize the object else we return default of the type. - For entityTypes this is not needed because we return null if key values are null. - For scalar which is server eval (i.e. only 1 column), we generate projectionBinding using resultType so we will get correct default back. - For scalar result which is client eval, we inject 1 into client projections. - For non scalar results (anonymous/nominal types), in client/server eval case, we inject 1 into projection/projectionMapping. Resolves #17287 --- .../Query/SqlExpressions/SelectExpression.cs | 33 ++++++- .../Query/GearsOfWarQueryInMemoryTest.cs | 6 ++ .../Query/ComplexNavigationsQueryTestBase.cs | 3 +- .../Query/GearsOfWarQueryTestBase.cs | 66 ++++++++++--- .../Query/QueryNavigationsTestBase.cs | 16 +++- .../ComplexNavigationsQuerySqlServerTest.cs | 6 +- .../Query/GearsOfWarQuerySqlServerTest.cs | 94 ++++++++++++------- .../Query/QueryNavigationsSqlServerTest.cs | 32 ++++++- 8 files changed, 197 insertions(+), 59 deletions(-) diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs index aa722b5e965..215ada2b24e 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs @@ -799,6 +799,31 @@ EntityProjectionExpression LiftEntityProjectionFromSubquery(EntityProjectionExpr public Expression AddSingleProjection(ShapedQueryExpression shapedQueryExpression) { var innerSelectExpression = (SelectExpression)shapedQueryExpression.QueryExpression; + var shaperExpression = shapedQueryExpression.ShaperExpression; + var innerExpression = RemoveConvert(shaperExpression); + if (!(innerExpression is EntityShaperExpression)) + { + var sentinelExpression = innerSelectExpression.Limit; + ProjectionBindingExpression dummyProjection; + if (innerSelectExpression.Projection.Any()) + { + var index = innerSelectExpression.AddToProjection(sentinelExpression); + dummyProjection = new ProjectionBindingExpression( + innerSelectExpression, index, sentinelExpression.Type); + } + else + { + innerSelectExpression._projectionMapping[new ProjectionMember()] = sentinelExpression; + dummyProjection = new ProjectionBindingExpression( + innerSelectExpression, new ProjectionMember(), sentinelExpression.Type); + } + + shaperExpression = Condition( + Equal(dummyProjection, Default(dummyProjection.Type)), + Default(shaperExpression.Type), + shaperExpression); + } + innerSelectExpression.ApplyProjection(); var projectionCount = innerSelectExpression.Projection.Count; AddOuterApply(innerSelectExpression, null); @@ -816,7 +841,13 @@ public Expression AddSingleProjection(ShapedQueryExpression shapedQueryExpressio } return new ShaperRemappingExpressionVisitor(this, innerSelectExpression, indexOffset) - .Visit(shapedQueryExpression.ShaperExpression); + .Visit(shaperExpression); + + static Expression RemoveConvert(Expression expression) + => expression is UnaryExpression unaryExpression + && unaryExpression.NodeType == ExpressionType.Convert + ? RemoveConvert(unaryExpression.Operand) + : expression; } public CollectionShaperExpression AddCollectionProjection( diff --git a/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs b/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs index b836b33c7c0..cfd6033b5c5 100644 --- a/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs @@ -70,5 +70,11 @@ public override Task GroupBy_with_boolean_groupin_key_thru_navigation_access(boo { return GroupBy_with_boolean_groupin_key_thru_navigation_access(isAsync); } + + [ConditionalTheory(Skip = "issue #17260")] + public override Task Select_subquery_projecting_single_constant_inside_anonymous(bool isAsync) + { + return base.Select_subquery_projecting_single_constant_inside_anonymous(isAsync); + } } } diff --git a/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs index a1c4bc6dbb8..97d34b1839b 100644 --- a/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs @@ -5904,8 +5904,7 @@ public virtual Task Lift_projection_mapping_when_pushing_down_subquery(bool isAs elementAsserter: (e, a) => { Assert.Equal(e.Id, a.Id); - // See issue#17287 - Assert.Equal(e.c1?.Id ?? 0, a.c1?.Id); + Assert.Equal(e.c1?.Id, a.c1?.Id); AssertCollection(e.c2, a.c2, elementSorter: i => i.Id, elementAsserter: (ie, ia) => Assert.Equal(ie.Id, ia.Id)); }); } diff --git a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs index b2434d84782..fc0e77dd47d 100644 --- a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs @@ -737,7 +737,8 @@ public virtual Task Select_enum_has_flag(bool isAsync) .Select( b => new { - hasFlagTrue = b.Rank.HasFlag(MilitaryRank.Corporal), hasFlagFalse = b.Rank.HasFlag(MilitaryRank.Sergeant) + hasFlagTrue = b.Rank.HasFlag(MilitaryRank.Corporal), + hasFlagFalse = b.Rank.HasFlag(MilitaryRank.Sergeant) })); } @@ -1251,11 +1252,11 @@ public virtual Task Where_compare_anonymous_types(bool isAsync) ss => from g in ss.Set() from o in ss.Set().OfType() where new - { - Name = g.LeaderNickname, - Squad = g.LeaderSquadId, - Five = 5 - } + { + Name = g.LeaderNickname, + Squad = g.LeaderSquadId, + Five = 5 + } == new { Name = o.Nickname, @@ -1282,8 +1283,8 @@ public virtual Task Where_compare_anonymous_types_with_uncorrelated_members(bool { return AssertQuery( isAsync, + // ReSharper disable once EqualExpressionComparison ss => from g in ss.Set() - // ReSharper disable once EqualExpressionComparison where new { Five = 5 } == new { Five = 5 } select g.Nickname); } @@ -3275,7 +3276,8 @@ where f is LocustHorde orderby f.Name select new { - Name = EF.Property(horde, "Name"), Eradicated = EF.Property((LocustHorde)f, "Eradicated") + Name = EF.Property(horde, "Name"), + Eradicated = EF.Property((LocustHorde)f, "Eradicated") }, ss => from f in ss.Set() where f is LocustHorde @@ -3443,7 +3445,7 @@ public virtual Task Comparing_two_collection_navigations_composite_key(bool isAs isAsync, ss => from g1 in ss.Set() from g2 in ss.Set() - // ReSharper disable once PossibleUnintendedReferenceComparison + // ReSharper disable once PossibleUnintendedReferenceComparison where g1.Weapons == g2.Weapons orderby g1.Nickname select new { Nickname1 = g1.Nickname, Nickname2 = g2.Nickname }, @@ -3596,7 +3598,8 @@ public virtual Task Project_collection_navigation_with_inheritance3(bool isAsync .Select( f => new { - f.Id, Gears = EF.Property>((Officer)((LocustHorde)f).Commander.DefeatedBy, "Reports") + f.Id, + Gears = EF.Property>((Officer)((LocustHorde)f).Commander.DefeatedBy, "Reports") }), ss => ss.Set() .Where(f => f is LocustHorde) @@ -5576,6 +5579,33 @@ public virtual Task Project_one_value_type_from_empty_collection(bool isAsync) s => new { s.Name, SquadId = s.Members.Where(m => m.HasSoulPatch).Select(m => m.SquadId).FirstOrDefault() })); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Project_one_value_type_converted_to_nullable_from_empty_collection(bool isAsync) + { + return AssertQuery( + isAsync, + ss => ss.Set().Where(s => s.Name == "Kilo").Select( + s => new { s.Name, SquadId = s.Members.Where(m => m.HasSoulPatch).Select(m => (int?)m.SquadId).FirstOrDefault() })); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Project_one_value_type_with_client_projection_from_empty_collection(bool isAsync) + { + return AssertQuery( + isAsync, + ss => ss.Set().Where(s => s.Name == "Kilo").Select( + s => new + { + s.Name, + SquadId = s.Members.Where(m => m.HasSoulPatch).Select(m => ClientFunction(m.SquadId, m.LeaderSquadId)).FirstOrDefault() + }), + elementSorter: s => s.Name); + } + + private static int ClientFunction(int a, int b) => a + b + 1; + [ConditionalTheory(Skip = "issue #15864")] [MemberData(nameof(IsAsyncData))] public virtual Task Filter_on_subquery_projecting_one_value_type_from_empty_collection(bool isAsync) @@ -5616,7 +5646,7 @@ public virtual Task Select_subquery_projecting_single_constant_bool(bool isAsync s => new { s.Name, Gear = s.Members.Where(g => g.HasSoulPatch).Select(g => true).FirstOrDefault() })); } - [ConditionalTheory(Skip = "Issue#17287")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Select_subquery_projecting_single_constant_inside_anonymous(bool isAsync) { @@ -5626,12 +5656,11 @@ public virtual Task Select_subquery_projecting_single_constant_inside_anonymous( s => new { s.Name, - Gear = s.Members.Where(g => g.HasSoulPatch).Select( - g => new { One = 1 }).FirstOrDefault() + Gear = s.Members.Where(g => g.HasSoulPatch).Select(g => new { One = 1 }).FirstOrDefault() })); } - [ConditionalTheory(Skip = "Issue#17287")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Select_subquery_projecting_multiple_constants_inside_anonymous(bool isAsync) { @@ -5712,7 +5741,14 @@ public virtual Task Select_subquery_projecting_single_constant_of_non_mapped_typ ss => ss.Set().Select( s => new { s.Name, Gear = s.Members.Where(g => g.HasSoulPatch).Select(g => new MyDTO()).FirstOrDefault() }), elementSorter: e => e.Name, - elementAsserter: (e, a) => Assert.Equal(e.Name, a.Name)); + elementAsserter: (e, a) => + { + Assert.Equal(e.Name, a.Name); + if (e.Gear == null) + { + Assert.Null(a.Gear); + } + }); } [ConditionalTheory(Skip = "issue #11567")] diff --git a/test/EFCore.Specification.Tests/Query/QueryNavigationsTestBase.cs b/test/EFCore.Specification.Tests/Query/QueryNavigationsTestBase.cs index 373a5954f39..514da2e9793 100644 --- a/test/EFCore.Specification.Tests/Query/QueryNavigationsTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/QueryNavigationsTestBase.cs @@ -257,12 +257,26 @@ public virtual Task Select_collection_FirstOrDefault_project_anonymous_type(bool { return AssertQuery( isAsync, - ss => ss.Set().OrderBy(c => c.CustomerID).Take(2).Select( + ss => ss.Set().Where(e => e.CustomerID.StartsWith("F")).OrderBy(c => c.CustomerID).Take(2).Select( c => c.Orders.OrderBy(o => o.OrderID).Select( o => new { o.CustomerID, o.OrderID }).FirstOrDefault()), assertOrder: true); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_collection_FirstOrDefault_project_anonymous_type_client_eval(bool isAsync) + { + return AssertQuery( + isAsync, + ss => ss.Set().Where(e => e.CustomerID.StartsWith("F")).OrderBy(c => c.CustomerID).Take(2).Select( + c => c.Orders.OrderBy(o => o.OrderID).Select( + o => new { o.CustomerID, OrderID = ClientFunction(o.OrderID, 5) }).FirstOrDefault()), + assertOrder: true); + } + + private static int ClientFunction(int a, int b) => a + b + 1; + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Select_collection_FirstOrDefault_project_entity(bool isAsync) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs index 90c533e96c3..76c1497e498 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs @@ -4411,15 +4411,15 @@ public override async Task Lift_projection_mapping_when_pushing_down_subquery(bo AssertSql( @"@__p_0='25' -SELECT [t].[Id], [t1].[Id], [l1].[Id] +SELECT [t].[Id], [t1].[Id], [t1].[c], [l1].[Id] FROM ( SELECT TOP(@__p_0) [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id] FROM [LevelOne] AS [l] ) AS [t] LEFT JOIN ( - SELECT [t0].[Id], [t0].[OneToMany_Required_Inverse2Id] + SELECT [t0].[Id], [t0].[c], [t0].[OneToMany_Required_Inverse2Id] FROM ( - SELECT [l0].[Id], [l0].[OneToMany_Required_Inverse2Id], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Required_Inverse2Id] ORDER BY [l0].[Id]) AS [row] + SELECT [l0].[Id], 1 AS [c], [l0].[OneToMany_Required_Inverse2Id], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Required_Inverse2Id] ORDER BY [l0].[Id]) AS [row] FROM [LevelTwo] AS [l0] ) AS [t0] WHERE [t0].[row] <= 1 diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index dbb27c091f2..7e3f37a8980 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -5684,6 +5684,38 @@ FROM [Squads] AS [s] WHERE ([s].[Name] = N'Kilo') AND [s].[Name] IS NOT NULL"); } + public override async Task Project_one_value_type_converted_to_nullable_from_empty_collection(bool isAsync) + { + await base.Project_one_value_type_converted_to_nullable_from_empty_collection(isAsync); + + AssertSql( + @"SELECT [s].[Name], ( + SELECT TOP(1) [g].[SquadId] + FROM [Gears] AS [g] + WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([s].[Id] = [g].[SquadId])) AND ([g].[HasSoulPatch] = CAST(1 AS bit))) AS [SquadId] +FROM [Squads] AS [s] +WHERE ([s].[Name] = N'Kilo') AND [s].[Name] IS NOT NULL"); + } + + public override async Task Project_one_value_type_with_client_projection_from_empty_collection(bool isAsync) + { + await base.Project_one_value_type_with_client_projection_from_empty_collection(isAsync); + + AssertSql( + @"SELECT [s].[Name], [t0].[SquadId], [t0].[LeaderSquadId], [t0].[c] +FROM [Squads] AS [s] +LEFT JOIN ( + SELECT [t].[SquadId], [t].[LeaderSquadId], [t].[c], [t].[Nickname] + FROM ( + SELECT [g].[SquadId], [g].[LeaderSquadId], 1 AS [c], [g].[Nickname], ROW_NUMBER() OVER(PARTITION BY [g].[SquadId] ORDER BY [g].[Nickname], [g].[SquadId]) AS [row] + FROM [Gears] AS [g] + WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] = CAST(1 AS bit)) + ) AS [t] + WHERE [t].[row] <= 1 +) AS [t0] ON [s].[Id] = [t0].[SquadId] +WHERE ([s].[Name] = N'Kilo') AND [s].[Name] IS NOT NULL"); + } + public override async Task Filter_on_subquery_projecting_one_value_type_from_empty_collection(bool isAsync) { await base.Filter_on_subquery_projecting_one_value_type_from_empty_collection(isAsync); @@ -5739,20 +5771,17 @@ public override async Task Select_subquery_projecting_single_constant_inside_ano await base.Select_subquery_projecting_single_constant_inside_anonymous(isAsync); AssertSql( - @"SELECT [s].[Name], [s].[Id] -FROM [Squads] AS [s]", - // - @"@_outer_Id='1' - -SELECT TOP(1) 1 -FROM [Gears] AS [g] -WHERE ([g].[Discriminator] IN (N'Officer', N'Gear') AND (@_outer_Id = [g].[SquadId])) AND ([g].[HasSoulPatch] = CAST(1 AS bit))", - // - @"@_outer_Id='2' - -SELECT TOP(1) 1 -FROM [Gears] AS [g] -WHERE ([g].[Discriminator] IN (N'Officer', N'Gear') AND (@_outer_Id = [g].[SquadId])) AND ([g].[HasSoulPatch] = CAST(1 AS bit))"); + @"SELECT [s].[Name], [t0].[c] +FROM [Squads] AS [s] +LEFT JOIN ( + SELECT [t].[c], [t].[Nickname], [t].[SquadId] + FROM ( + SELECT 1 AS [c], [g].[Nickname], [g].[SquadId], ROW_NUMBER() OVER(PARTITION BY [g].[SquadId] ORDER BY [g].[Nickname], [g].[SquadId]) AS [row] + FROM [Gears] AS [g] + WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] = CAST(1 AS bit)) + ) AS [t] + WHERE [t].[row] <= 1 +) AS [t0] ON [s].[Id] = [t0].[SquadId]"); } public override async Task Select_subquery_projecting_multiple_constants_inside_anonymous(bool isAsync) @@ -5760,20 +5789,17 @@ public override async Task Select_subquery_projecting_multiple_constants_inside_ await base.Select_subquery_projecting_multiple_constants_inside_anonymous(isAsync); AssertSql( - @"SELECT [s].[Name], [s].[Id] -FROM [Squads] AS [s]", - // - @"@_outer_Id='1' - -SELECT TOP(1) 1 -FROM [Gears] AS [g] -WHERE ([g].[Discriminator] IN (N'Officer', N'Gear') AND (@_outer_Id = [g].[SquadId])) AND ([g].[HasSoulPatch] = CAST(1 AS bit))", - // - @"@_outer_Id='2' - -SELECT TOP(1) 1 -FROM [Gears] AS [g] -WHERE ([g].[Discriminator] IN (N'Officer', N'Gear') AND (@_outer_Id = [g].[SquadId])) AND ([g].[HasSoulPatch] = CAST(1 AS bit))"); + @"SELECT [s].[Name], [t0].[c], [t0].[c0], [t0].[c1] +FROM [Squads] AS [s] +LEFT JOIN ( + SELECT [t].[c], [t].[c0], [t].[c1], [t].[Nickname], [t].[SquadId] + FROM ( + SELECT CAST(1 AS bit) AS [c], CAST(0 AS bit) AS [c0], 1 AS [c1], [g].[Nickname], [g].[SquadId], ROW_NUMBER() OVER(PARTITION BY [g].[SquadId] ORDER BY [g].[Nickname], [g].[SquadId]) AS [row] + FROM [Gears] AS [g] + WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] = CAST(1 AS bit)) + ) AS [t] + WHERE [t].[row] <= 1 +) AS [t0] ON [s].[Id] = [t0].[SquadId]"); } public override async Task Include_with_order_by_constant(bool isAsync) @@ -5827,12 +5853,12 @@ public override async Task Select_subquery_projecting_single_constant_null_of_no await base.Select_subquery_projecting_single_constant_null_of_non_mapped_type(isAsync); AssertSql( - @"SELECT [s].[Name] + @"SELECT [s].[Name], [t0].[c] FROM [Squads] AS [s] LEFT JOIN ( - SELECT [t].[Nickname], [t].[SquadId] + SELECT [t].[c], [t].[Nickname], [t].[SquadId] FROM ( - SELECT [g].[Nickname], [g].[SquadId], ROW_NUMBER() OVER(PARTITION BY [g].[SquadId] ORDER BY [g].[Nickname], [g].[SquadId]) AS [row] + SELECT 1 AS [c], [g].[Nickname], [g].[SquadId], ROW_NUMBER() OVER(PARTITION BY [g].[SquadId] ORDER BY [g].[Nickname], [g].[SquadId]) AS [row] FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] = CAST(1 AS bit)) ) AS [t] @@ -5845,12 +5871,12 @@ public override async Task Select_subquery_projecting_single_constant_of_non_map await base.Select_subquery_projecting_single_constant_of_non_mapped_type(isAsync); AssertSql( - @"SELECT [s].[Name] + @"SELECT [s].[Name], [t0].[c] FROM [Squads] AS [s] LEFT JOIN ( - SELECT [t].[Nickname], [t].[SquadId] + SELECT [t].[c], [t].[Nickname], [t].[SquadId] FROM ( - SELECT [g].[Nickname], [g].[SquadId], ROW_NUMBER() OVER(PARTITION BY [g].[SquadId] ORDER BY [g].[Nickname], [g].[SquadId]) AS [row] + SELECT 1 AS [c], [g].[Nickname], [g].[SquadId], ROW_NUMBER() OVER(PARTITION BY [g].[SquadId] ORDER BY [g].[Nickname], [g].[SquadId]) AS [row] FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] = CAST(1 AS bit)) ) AS [t] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/QueryNavigationsSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/QueryNavigationsSqlServerTest.cs index 9d3b127f051..6d0e6309598 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/QueryNavigationsSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/QueryNavigationsSqlServerTest.cs @@ -167,16 +167,42 @@ public override async Task Select_collection_FirstOrDefault_project_anonymous_ty AssertSql( @"@__p_0='2' -SELECT [t1].[CustomerID], [t1].[OrderID] +SELECT [t1].[CustomerID], [t1].[OrderID], [t1].[c] FROM ( SELECT TOP(@__p_0) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] + WHERE [c].[CustomerID] LIKE N'F%' ORDER BY [c].[CustomerID] ) AS [t] LEFT JOIN ( - SELECT [t0].[CustomerID], [t0].[OrderID] + SELECT [t0].[CustomerID], [t0].[OrderID], [t0].[c] FROM ( - SELECT [o].[CustomerID], [o].[OrderID], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID]) AS [row] + SELECT [o].[CustomerID], [o].[OrderID], 1 AS [c], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID]) AS [row] + FROM [Orders] AS [o] + ) AS [t0] + WHERE [t0].[row] <= 1 +) AS [t1] ON [t].[CustomerID] = [t1].[CustomerID] +ORDER BY [t].[CustomerID]"); + } + + public override async Task Select_collection_FirstOrDefault_project_anonymous_type_client_eval(bool isAsync) + { + await base.Select_collection_FirstOrDefault_project_anonymous_type_client_eval(isAsync); + + AssertSql( + @"@__p_0='2' + +SELECT [t1].[CustomerID], [t1].[OrderID], [t1].[c] +FROM ( + SELECT TOP(@__p_0) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] + FROM [Customers] AS [c] + WHERE [c].[CustomerID] LIKE N'F%' + ORDER BY [c].[CustomerID] +) AS [t] +LEFT JOIN ( + SELECT [t0].[CustomerID], [t0].[OrderID], [t0].[c] + FROM ( + SELECT [o].[CustomerID], [o].[OrderID], 1 AS [c], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID]) AS [row] FROM [Orders] AS [o] ) AS [t0] WHERE [t0].[row] <= 1 From 68f725c06a3af35a670afe4c84d66656511c2174 Mon Sep 17 00:00:00 2001 From: Smit Patel Date: Fri, 1 Nov 2019 14:26:43 -0700 Subject: [PATCH 2/4] Query: Process Cast to interface/object in Navigation expansion Resolves #18087 Navigation expansion prunes Cast to implemented interface or object Navigation expansion puts cast to non-implemented interface --- .../NavigationExpandingExpressionVisitor.cs | 46 ++++---- .../Query/QueryBugsTest.cs | 111 ++++++++++++++++++ 2 files changed, 137 insertions(+), 20 deletions(-) diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs index cd709cc2f13..b4cbd79faa8 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs @@ -1260,38 +1260,44 @@ private Expression ProcessCastOfType( MethodInfo genericMethod, Type castType) { + if ((castType.IsInterface + && castType.IsAssignableFrom(source.PendingSelector.Type)) + || castType == typeof(object)) + { + // Casting to base/implementing interface is redundant + return source; + } + source = (NavigationExpansionExpression)_pendingSelectorExpandingExpressionVisitor.Visit(source); var newStructure = SnapshotExpression(source.PendingSelector); var queryable = Reduce(source); var result = Expression.Call(genericMethod.MakeGenericMethod(castType), queryable); - if (newStructure is EntityReference entityReference) + if (newStructure is EntityReference entityReference + && entityReference.EntityType.GetTypesInHierarchy() + .FirstOrDefault(et => et.ClrType == castType) is EntityType castEntityType) { - var castEntityType = entityReference.EntityType.GetTypesInHierarchy().FirstOrDefault(et => et.ClrType == castType); - if (castEntityType != null) + var newEntityReference = new EntityReference(castEntityType); + if (entityReference.IsOptional) { - var newEntityReference = new EntityReference(castEntityType); - if (entityReference.IsOptional) - { - newEntityReference.MarkAsOptional(); - } - - newEntityReference.SetIncludePaths(entityReference.IncludePaths); + newEntityReference.MarkAsOptional(); + } - // Prune includes for sibling types - var siblingNavigations = newEntityReference.IncludePaths.Keys - .Where( - n => !castEntityType.IsAssignableFrom(n.DeclaringEntityType) - && !n.DeclaringEntityType.IsAssignableFrom(castEntityType)).ToList(); + newEntityReference.SetIncludePaths(entityReference.IncludePaths); - foreach (var navigation in siblingNavigations) - { - newEntityReference.IncludePaths.Remove(navigation); - } + // Prune includes for sibling types + var siblingNavigations = newEntityReference.IncludePaths.Keys + .Where( + n => !castEntityType.IsAssignableFrom(n.DeclaringEntityType) + && !n.DeclaringEntityType.IsAssignableFrom(castEntityType)).ToList(); - newStructure = newEntityReference; + foreach (var navigation in siblingNavigations) + { + newEntityReference.IncludePaths.Remove(navigation); } + + newStructure = newEntityReference; } else { diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs index 004d512c2af..b2cad03cbb1 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs @@ -7259,6 +7259,117 @@ public BugContext17794(DbContextOptions options) #endregion + #region Issue18087 + + [ConditionalFact] + public void Cast_to_implemented_interface_is_removed_from_expression_tree() + { + using var _ = CreateDatabase18087(); + using var context = new BugContext18087(_options); + + var queryBase = (IQueryable)context.MockEntities; + var id = 1; + var query = queryBase.Cast().FirstOrDefault(x => x.Id == id); + + Assert.Equal(1, query.Id); + + AssertSql( + @"@__id_0='1' + +SELECT TOP(1) [m].[Id], [m].[Name], [m].[NavigationEntityId] +FROM [MockEntities] AS [m] +WHERE [m].[Id] = @__id_0"); + } + + [ConditionalFact] + public void Cast_to_object_is_removed_from_expression_tree() + { + using var _ = CreateDatabase18087(); + using var context = new BugContext18087(_options); + + var queryBase = (IQueryable)context.MockEntities; + var query = queryBase.Cast().Count(); + + Assert.Equal(3, query); + + AssertSql( + @"SELECT COUNT(*) +FROM [MockEntities] AS [m]"); + } + + [ConditionalFact] + public void Cast_to_non_implemented_interface_is_not_removed_from_expression_tree() + { + using var _ = CreateDatabase18087(); + using var context = new BugContext18087(_options); + + var queryBase = (IQueryable)context.MockEntities; + var id = 1; + + var message = Assert.Throws( + () => queryBase.Cast().FirstOrDefault(x => x.Id == id)).Message; + + Assert.Equal( + CoreStrings.TranslationFailed(@"DbSet .Cast() .Where(e => e.Id == __id_0)"), + message.Replace("\r", "").Replace("\n", "")); + } + + private SqlServerTestStore CreateDatabase18087() + => CreateTestStore( + () => new BugContext18087(_options), + context => + { + context.AddRange(new MockEntity() + { + Name = "Entity1", + NavigationEntity = null + }, + new MockEntity() + { + Name = "Entity2", + NavigationEntity = null + }, + new MockEntity() + { + Name = "NewEntity", + NavigationEntity = null + }); + + context.SaveChanges(); + + ClearLog(); + }); + + private interface IDomainEntity + { + int Id { get; set; } + } + + private interface IDummyEntity + { + int Id { get; set; } + } + + private class MockEntity : IDomainEntity + { + public int Id { get; set; } + public string Name { get; set; } + + public MockEntity NavigationEntity { get; set; } + } + + private class BugContext18087 : DbContext + { + public BugContext18087(DbContextOptions options) + : base(options) + { + } + + public DbSet MockEntities { get; set; } + } + + #endregion + private DbContextOptions _options; private SqlServerTestStore CreateTestStore( From dd92ba3dc60186cb1a36a925824f660da92d8f42 Mon Sep 17 00:00:00 2001 From: Maurycy Markowski Date: Thu, 24 Oct 2019 18:06:01 -0700 Subject: [PATCH 3/4] Additional perf improvements around null semantics scenarios Resolves #17543 - Queries really slow due to null checks Resolves #18525 - Query: optimize binary expression AndAlso and OrElse where left and right are the same Resolves #18547 - DbFunctions compared to NULL are ignored and break the query builder #17543 Before when rewriting null comparisons we would always remove possibility of nulls in the resulting expression. This is not always needed, specifically in predicates, where it doesn't really matter if expression returns false or null - the result is the same. Now we detect those cases and apply "simplified" null expansion which should lead to better performance. #18525 Null semantics initially expands expressions to a verbose form which then gets simplified in query optimizer. One of the optimizations added is when we do AND/OR where both sides are the same. Other small improvements have been added in this change also. #18547 Previously we assumed that function can only be null if at least one of its arguments is null. This is the case for most built-in functions, but not all. This also goes for user defined functions which can return arbitrary results. Fix is to treat all functions as potentially nullable. This leads to worse queries is some cases, but is also mitigated by other improvements added along side. In the future we will provide metadata to better determine given function's nullability. Also fixed a few small bug found along the way - incorrect Equals comparison for SqlExpression, for cases when TypeMapping was null. Additional refactoring: - removed the second pass of sql optimizations (we do it later when sniffing parameter values anyway) - consolidated NullComparisonTransformingExpressionVisitor into SqlExpressionOptimizingExpressionVisitor --- ...ComparisonTransformingExpressionVisitor.cs | 35 -- ...NullSemanticsRewritingExpressionVisitor.cs | 442 ++++++++++--- ...eterValueBasedSelectExpressionOptimizer.cs | 104 +-- ...qlExpressionOptimizingExpressionVisitor.cs | 520 ++++++++++----- ...RelationalQueryTranslationPostprocessor.cs | 1 - .../Query/SqlExpressionVisitor.cs | 56 +- .../Query/SqlExpressions/SqlExpression.cs | 3 +- ...rchConditionConvertingExpressionVisitor.cs | 8 +- .../SqlServerQueryTranslationPostprocessor.cs | 1 - .../Query/SimpleQueryCosmosTest.cs | 6 + .../Query/SimpleQueryTestBase.Functions.cs | 9 + .../BuiltInDataTypesSqlServerTest.cs | 16 +- .../LoadSqlServerTest.cs | 82 +-- .../ComplexNavigationsQuerySqlServerTest.cs | 104 ++- .../Query/DbFunctionsSqlServerTest.cs | 12 +- .../Query/FiltersSqlServerTest.cs | 38 +- .../Query/FromSqlQuerySqlServerTest.cs | 22 +- .../Query/FunkyDataQuerySqlServerTest.cs | 46 +- .../Query/GearsOfWarQuerySqlServerTest.cs | 591 ++++++++---------- .../Query/GroupByQuerySqlServerTest.cs | 6 +- .../Query/IncludeAsyncSqlServerTest.cs | 4 +- .../Query/IncludeSqlServerTest.cs | 28 +- .../Query/InheritanceSqlServerTest.cs | 6 +- .../Query/NullSemanticsQuerySqlServerTest.cs | 71 +-- .../Query/OwnedQuerySqlServerTest.cs | 6 +- .../Query/QueryBugsTest.cs | 47 +- .../Query/QueryNavigationsSqlServerTest.cs | 72 +-- .../SimpleQuerySqlServerTest.Functions.cs | 150 ++--- .../SimpleQuerySqlServerTest.JoinGroupJoin.cs | 18 +- ...impleQuerySqlServerTest.KeylessEntities.cs | 16 +- ...impleQuerySqlServerTest.ResultOperators.cs | 59 +- .../Query/SimpleQuerySqlServerTest.Select.cs | 86 +-- .../SimpleQuerySqlServerTest.SetOperations.cs | 72 +-- .../Query/SimpleQuerySqlServerTest.Where.cs | 166 +++-- .../Query/SimpleQuerySqlServerTest.cs | 255 +++----- .../SpatialQuerySqlServerGeographyTest.cs | 2 +- .../SpatialQuerySqlServerGeometryTest.cs | 2 +- .../Query/UdfDbFunctionSqlServerTests.cs | 14 +- .../UpdatesSqlServerTest.cs | 4 +- .../Query/FiltersSqliteTest.cs | 2 +- .../Query/SimpleQuerySqliteTest.cs | 60 +- 41 files changed, 1795 insertions(+), 1447 deletions(-) delete mode 100644 src/EFCore.Relational/Query/Internal/NullComparisonTransformingExpressionVisitor.cs diff --git a/src/EFCore.Relational/Query/Internal/NullComparisonTransformingExpressionVisitor.cs b/src/EFCore.Relational/Query/Internal/NullComparisonTransformingExpressionVisitor.cs deleted file mode 100644 index 983640ab8a5..00000000000 --- a/src/EFCore.Relational/Query/Internal/NullComparisonTransformingExpressionVisitor.cs +++ /dev/null @@ -1,35 +0,0 @@ -// 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.Linq.Expressions; -using Microsoft.EntityFrameworkCore.Query.SqlExpressions; - -namespace Microsoft.EntityFrameworkCore.Query.Internal -{ - public class NullComparisonTransformingExpressionVisitor : ExpressionVisitor - { - protected override Expression VisitExtension(Expression extensionExpression) - { - if (extensionExpression is SqlBinaryExpression sqlBinary - && (sqlBinary.OperatorType == ExpressionType.Equal - || sqlBinary.OperatorType == ExpressionType.NotEqual)) - { - var isLeftNull = sqlBinary.Left is SqlConstantExpression leftConstant && leftConstant.Value == null; - var isRightNull = sqlBinary.Right is SqlConstantExpression rightConstant && rightConstant.Value == null; - - if (isLeftNull || isRightNull) - { - var nonNull = isLeftNull ? sqlBinary.Right : sqlBinary.Left; - - return new SqlUnaryExpression( - sqlBinary.OperatorType, - nonNull, - sqlBinary.Type, - sqlBinary.TypeMapping); - } - } - - return base.VisitExtension(extensionExpression); - } - } -} diff --git a/src/EFCore.Relational/Query/Internal/NullSemanticsRewritingExpressionVisitor.cs b/src/EFCore.Relational/Query/Internal/NullSemanticsRewritingExpressionVisitor.cs index 88adca66232..8497a115581 100644 --- a/src/EFCore.Relational/Query/Internal/NullSemanticsRewritingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Internal/NullSemanticsRewritingExpressionVisitor.cs @@ -8,190 +8,322 @@ namespace Microsoft.EntityFrameworkCore.Query.Internal { - public class NullSemanticsRewritingExpressionVisitor : ExpressionVisitor + public class NullSemanticsRewritingExpressionVisitor : SqlExpressionVisitor { private readonly ISqlExpressionFactory _sqlExpressionFactory; private bool _isNullable; + private bool _canOptimize; private readonly List _nonNullableColumns = new List(); public NullSemanticsRewritingExpressionVisitor(ISqlExpressionFactory sqlExpressionFactory) { _sqlExpressionFactory = sqlExpressionFactory; + _canOptimize = true; } - protected override Expression VisitExtension(Expression extensionExpression) + protected override Expression VisitCase(CaseExpression caseExpression) { - switch (extensionExpression) - { - case SqlConstantExpression sqlConstantExpression: - return VisitSqlConstantExpression(sqlConstantExpression); - - case ColumnExpression columnExpression: - return VisitColumnExpression(columnExpression); - - case SqlParameterExpression sqlParameterExpression: - return VisitSqlParameterExpression(sqlParameterExpression); - - case SqlUnaryExpression sqlUnaryExpression: - return VisitSqlUnaryExpression(sqlUnaryExpression); - - case LikeExpression likeExpression: - return VisitLikeExpression(likeExpression); - - case SqlFunctionExpression sqlFunctionExpression: - return VisitSqlFunctionExpression(sqlFunctionExpression); + _isNullable = false; + // if there is no 'else' there is a possibility of null, when none of the conditions are met + // otherwise the result is nullable if any of the WhenClause results OR ElseResult is nullable + var isNullable = caseExpression.ElseResult == null; - case SqlBinaryExpression sqlBinaryExpression: - return VisitSqlBinaryExpression(sqlBinaryExpression); + var canOptimize = _canOptimize; + var testIsCondition = caseExpression.Operand == null; + _canOptimize = false; + var newOperand = (SqlExpression)Visit(caseExpression.Operand); + var newWhenClauses = new List(); + foreach (var whenClause in caseExpression.WhenClauses) + { + _canOptimize = testIsCondition; + var newTest = (SqlExpression)Visit(whenClause.Test); + _canOptimize = false; + _isNullable = false; + var newResult = (SqlExpression)Visit(whenClause.Result); + isNullable |= _isNullable; + newWhenClauses.Add(new CaseWhenClause(newTest, newResult)); + } - case CaseExpression caseExpression: - return VisitCaseExpression(caseExpression); + _canOptimize = false; + var newElseResult = (SqlExpression)Visit(caseExpression.ElseResult); + _isNullable |= isNullable; + _canOptimize = canOptimize; - case InnerJoinExpression innerJoinExpression: - return VisitInnerJoinExpression(innerJoinExpression); + return caseExpression.Update(newOperand, newWhenClauses, newElseResult); + } - case LeftJoinExpression leftJoinExpression: - return VisitLeftJoinExpression(leftJoinExpression); + protected override Expression VisitColumn(ColumnExpression columnExpression) + { + _isNullable = !_nonNullableColumns.Contains(columnExpression) && columnExpression.IsNullable; - case ScalarSubqueryExpression subSelectExpression: - var result = base.VisitExtension(subSelectExpression); - _isNullable = true; + return columnExpression; + } - return result; + protected override Expression VisitCrossApply(CrossApplyExpression crossApplyExpression) + { + var canOptimize = _canOptimize; + _canOptimize = false; + var table = (TableExpressionBase)Visit(crossApplyExpression.Table); + _canOptimize = canOptimize; - default: - return base.VisitExtension(extensionExpression); - } + return crossApplyExpression.Update(table); } - private SqlConstantExpression VisitSqlConstantExpression(SqlConstantExpression sqlConstantExpression) + protected override Expression VisitCrossJoin(CrossJoinExpression crossJoinExpression) { - _isNullable = sqlConstantExpression.Value == null; + var canOptimize = _canOptimize; + _canOptimize = false; + var table = (TableExpressionBase)Visit(crossJoinExpression.Table); + _canOptimize = canOptimize; - return sqlConstantExpression; + return crossJoinExpression.Update(table); } - private ColumnExpression VisitColumnExpression(ColumnExpression columnExpression) + protected override Expression VisitExcept(ExceptExpression exceptExpression) { - _isNullable = !_nonNullableColumns.Contains(columnExpression) && columnExpression.IsNullable; + var canOptimize = _canOptimize; + _canOptimize = false; + var source1 = (SelectExpression)Visit(exceptExpression.Source1); + var source2 = (SelectExpression)Visit(exceptExpression.Source2); + _canOptimize = canOptimize; - return columnExpression; + return exceptExpression.Update(source1, source2); } - private SqlParameterExpression VisitSqlParameterExpression(SqlParameterExpression sqlParameterExpression) + protected override Expression VisitExists(ExistsExpression existsExpression) { - // at this point we assume every parameter is nullable, we will filter out the non-nullable ones once we know the actual values - _isNullable = true; + var canOptimize = _canOptimize; + _canOptimize = false; + var newSubquery = (SelectExpression)Visit(existsExpression.Subquery); + _canOptimize = canOptimize; - return sqlParameterExpression; + return existsExpression.Update(newSubquery); } - private SqlUnaryExpression VisitSqlUnaryExpression(SqlUnaryExpression sqlUnaryExpression) + protected override Expression VisitFromSql(FromSqlExpression fromSqlExpression) + => fromSqlExpression; + + protected override Expression VisitIn(InExpression inExpression) { + var canOptimize = _canOptimize; + _canOptimize = false; _isNullable = false; - var newOperand = (SqlExpression)Visit(sqlUnaryExpression.Operand); + var item = (SqlExpression)Visit(inExpression.Item); + var isNullable = _isNullable; + _isNullable = false; + var subquery = (SelectExpression)Visit(inExpression.Subquery); + isNullable |= _isNullable; + _isNullable = false; + var values = (SqlExpression)Visit(inExpression.Values); + _isNullable |= isNullable; + _canOptimize = canOptimize; - // IsNull/IsNotNull - if (sqlUnaryExpression.OperatorType == ExpressionType.Equal - || sqlUnaryExpression.OperatorType == ExpressionType.NotEqual) - { - _isNullable = false; - } + return inExpression.Update(item, values, subquery); + } - return sqlUnaryExpression.Update(newOperand); + protected override Expression VisitIntersect(IntersectExpression intersectExpression) + { + var canOptimize = _canOptimize; + _canOptimize = false; + var source1 = (SelectExpression)Visit(intersectExpression.Source1); + var source2 = (SelectExpression)Visit(intersectExpression.Source2); + _canOptimize = canOptimize; + + return intersectExpression.Update(source1, source2); } - private LikeExpression VisitLikeExpression(LikeExpression likeExpression) + protected override Expression VisitLike(LikeExpression likeExpression) { + var canOptimize = _canOptimize; + _canOptimize = false; _isNullable = false; var newMatch = (SqlExpression)Visit(likeExpression.Match); var isNullable = _isNullable; + _isNullable = false; var newPattern = (SqlExpression)Visit(likeExpression.Pattern); isNullable |= _isNullable; + _isNullable = false; var newEscapeChar = (SqlExpression)Visit(likeExpression.EscapeChar); _isNullable |= isNullable; + _canOptimize = canOptimize; return likeExpression.Update(newMatch, newPattern, newEscapeChar); } - private InnerJoinExpression VisitInnerJoinExpression(InnerJoinExpression innerJoinExpression) + protected override Expression VisitInnerJoin(InnerJoinExpression innerJoinExpression) { + var canOptimize = _canOptimize; + _canOptimize = false; var newTable = (TableExpressionBase)Visit(innerJoinExpression.Table); var newJoinPredicate = VisitJoinPredicate((SqlBinaryExpression)innerJoinExpression.JoinPredicate); + _canOptimize = canOptimize; return innerJoinExpression.Update(newTable, newJoinPredicate); } - private LeftJoinExpression VisitLeftJoinExpression(LeftJoinExpression leftJoinExpression) + protected override Expression VisitLeftJoin(LeftJoinExpression leftJoinExpression) { + var canOptimize = _canOptimize; + _canOptimize = false; var newTable = (TableExpressionBase)Visit(leftJoinExpression.Table); var newJoinPredicate = VisitJoinPredicate((SqlBinaryExpression)leftJoinExpression.JoinPredicate); + _canOptimize = canOptimize; return leftJoinExpression.Update(newTable, newJoinPredicate); } private SqlExpression VisitJoinPredicate(SqlBinaryExpression predicate) { + var canOptimize = _canOptimize; + _canOptimize = true; + if (predicate.OperatorType == ExpressionType.Equal) { var newLeft = (SqlExpression)Visit(predicate.Left); var newRight = (SqlExpression)Visit(predicate.Right); + _canOptimize = canOptimize; return predicate.Update(newLeft, newRight); } if (predicate.OperatorType == ExpressionType.AndAlso) { - return VisitSqlBinaryExpression(predicate); + var newPredicate = (SqlExpression)VisitSqlBinary(predicate); + _canOptimize = canOptimize; + + return newPredicate; } throw new InvalidOperationException("Unexpected join predicate shape: " + predicate); } - private CaseExpression VisitCaseExpression(CaseExpression caseExpression) + protected override Expression VisitOrdering(OrderingExpression orderingExpression) { - _isNullable = false; - // if there is no 'else' there is a possibility of null, when none of the conditions are met - // otherwise the result is nullable if any of the WhenClause results OR ElseResult is nullable - var isNullable = caseExpression.ElseResult == null; + var expression = (SqlExpression)Visit(orderingExpression.Expression); - var newOperand = (SqlExpression)Visit(caseExpression.Operand); - var newWhenClauses = new List(); - foreach (var whenClause in caseExpression.WhenClauses) + return orderingExpression.Update(expression); + } + + protected override Expression VisitOuterApply(OuterApplyExpression outerApplyExpression) + { + var canOptimize = _canOptimize; + _canOptimize = false; + var table = (TableExpressionBase)Visit(outerApplyExpression.Table); + _canOptimize = canOptimize; + + return outerApplyExpression.Update(table); + } + + protected override Expression VisitProjection(ProjectionExpression projectionExpression) + { + var expression = (SqlExpression)Visit(projectionExpression.Expression); + + return projectionExpression.Update(expression); + } + + protected override Expression VisitRowNumber(RowNumberExpression rowNumberExpression) + { + var canOptimize = _canOptimize; + _canOptimize = false; + var changed = false; + var partitions = new List(); + foreach (var partition in rowNumberExpression.Partitions) { - var newTest = (SqlExpression)Visit(whenClause.Test); - var newResult = (SqlExpression)Visit(whenClause.Result); - isNullable |= _isNullable; - newWhenClauses.Add(new CaseWhenClause(newTest, newResult)); + var newPartition = (SqlExpression)Visit(partition); + changed |= newPartition != partition; + partitions.Add(newPartition); } - var newElseResult = (SqlExpression)Visit(caseExpression.ElseResult); - _isNullable |= isNullable; + var orderings = new List(); + foreach (var ordering in rowNumberExpression.Orderings) + { + var newOrdering = (OrderingExpression)Visit(ordering); + changed |= newOrdering != ordering; + orderings.Add(newOrdering); + } - return caseExpression.Update(newOperand, newWhenClauses, newElseResult); + _canOptimize = canOptimize; + + return rowNumberExpression.Update(partitions, orderings); } - private SqlFunctionExpression VisitSqlFunctionExpression(SqlFunctionExpression sqlFunctionExpression) + protected override Expression VisitSelect(SelectExpression selectExpression) { - _isNullable = false; - var newInstance = (SqlExpression)Visit(sqlFunctionExpression.Instance); - var isNullable = _isNullable; - var newArguments = new SqlExpression[sqlFunctionExpression.Arguments.Count]; - for (var i = 0; i < newArguments.Length; i++) + var changed = false; + var canOptimize = _canOptimize; + var projections = new List(); + _canOptimize = false; + foreach (var item in selectExpression.Projection) { - newArguments[i] = (SqlExpression)Visit(sqlFunctionExpression.Arguments[i]); - isNullable |= _isNullable; + var updatedProjection = (ProjectionExpression)Visit(item); + projections.Add(updatedProjection); + changed |= updatedProjection != item; } - _isNullable = isNullable; + var tables = new List(); + foreach (var table in selectExpression.Tables) + { + var newTable = (TableExpressionBase)Visit(table); + changed |= newTable != table; + tables.Add(newTable); + } - return sqlFunctionExpression.Update(newInstance, newArguments); + _canOptimize = true; + var predicate = (SqlExpression)Visit(selectExpression.Predicate); + changed |= predicate != selectExpression.Predicate; + + var groupBy = new List(); + _canOptimize = false; + foreach (var groupingKey in selectExpression.GroupBy) + { + var newGroupingKey = (SqlExpression)Visit(groupingKey); + changed |= newGroupingKey != groupingKey; + groupBy.Add(newGroupingKey); + } + + _canOptimize = true; + var havingExpression = (SqlExpression)Visit(selectExpression.Having); + changed |= havingExpression != selectExpression.Having; + + var orderings = new List(); + _canOptimize = false; + foreach (var ordering in selectExpression.Orderings) + { + var orderingExpression = (SqlExpression)Visit(ordering.Expression); + changed |= orderingExpression != ordering.Expression; + orderings.Add(ordering.Update(orderingExpression)); + } + + var offset = (SqlExpression)Visit(selectExpression.Offset); + changed |= offset != selectExpression.Offset; + + var limit = (SqlExpression)Visit(selectExpression.Limit); + changed |= limit != selectExpression.Limit; + + _canOptimize = canOptimize; + + // we assume SelectExpression can always be null + // (e.g. projecting non-nullable column but with predicate that filters out all rows) + _isNullable = true; + + return changed + ? selectExpression.Update( + projections, tables, predicate, groupBy, havingExpression, orderings, limit, offset, selectExpression.IsDistinct, + selectExpression.Alias) + : selectExpression; } - private SqlBinaryExpression VisitSqlBinaryExpression(SqlBinaryExpression sqlBinaryExpression) + protected override Expression VisitSqlBinary(SqlBinaryExpression sqlBinaryExpression) { _isNullable = false; + var canOptimize = _canOptimize; + + // for SqlServer we could also allow optimize on children of ExpressionType.Equal + // because they get converted to CASE blocks anyway, but for other providers it's incorrect + // once/if null semantics optimizations are provider-specific we can enable it + _canOptimize = _canOptimize && (sqlBinaryExpression.OperatorType == ExpressionType.AndAlso + || sqlBinaryExpression.OperatorType == ExpressionType.OrElse); var nonNullableColumns = new List(); if (sqlBinaryExpression.OperatorType == ExpressionType.AndAlso) @@ -219,6 +351,7 @@ private SqlBinaryExpression VisitSqlBinaryExpression(SqlBinaryExpression sqlBina if (sqlBinaryExpression.OperatorType == ExpressionType.Coalesce) { _isNullable = leftNullable && rightNullable; + _canOptimize = canOptimize; return sqlBinaryExpression.Update(newLeft, newRight); } @@ -226,6 +359,33 @@ private SqlBinaryExpression VisitSqlBinaryExpression(SqlBinaryExpression sqlBina if (sqlBinaryExpression.OperatorType == ExpressionType.Equal || sqlBinaryExpression.OperatorType == ExpressionType.NotEqual) { + var leftConstantNull = newLeft is SqlConstantExpression leftConstant && leftConstant.Value == null; + var rightConstantNull = newRight is SqlConstantExpression rightConstant && rightConstant.Value == null; + + // a == null -> a IS NULL + // a != null -> a IS NOT NULL + if (rightConstantNull) + { + _isNullable = false; + _canOptimize = canOptimize; + + return sqlBinaryExpression.OperatorType == ExpressionType.Equal + ? _sqlExpressionFactory.IsNull(newLeft) + : _sqlExpressionFactory.IsNotNull(newLeft); + } + + // null == a -> a IS NULL + // null != a -> a IS NOT NULL + if (leftConstantNull) + { + _isNullable = false; + _canOptimize = canOptimize; + + return sqlBinaryExpression.OperatorType == ExpressionType.Equal + ? _sqlExpressionFactory.IsNull(newRight) + : _sqlExpressionFactory.IsNotNull(newRight); + } + var leftUnary = newLeft as SqlUnaryExpression; var rightUnary = newRight as SqlUnaryExpression; @@ -245,9 +405,37 @@ private SqlBinaryExpression VisitSqlBinaryExpression(SqlBinaryExpression sqlBina var leftIsNull = _sqlExpressionFactory.IsNull(newLeft); var rightIsNull = _sqlExpressionFactory.IsNull(newRight); + // optimized expansion which doesn't distinguish between null and false + if (canOptimize + && sqlBinaryExpression.OperatorType == ExpressionType.Equal + && !leftNegated + && !rightNegated) + { + // when we use optimized form, the result can still be nullable + if (leftNullable && rightNullable) + { + _isNullable = true; + _canOptimize = canOptimize; + + return _sqlExpressionFactory.OrElse( + _sqlExpressionFactory.Equal(newLeft, newRight), + _sqlExpressionFactory.AndAlso(leftIsNull, rightIsNull)); + } + + if ((leftNullable && !rightNullable) + || (!leftNullable && rightNullable)) + { + _isNullable = true; + _canOptimize = canOptimize; + + return _sqlExpressionFactory.Equal(newLeft, newRight); + } + } + // doing a full null semantics rewrite - removing all nulls from truth table // this will NOT be correct once we introduce simplified null semantics _isNullable = false; + _canOptimize = canOptimize; if (sqlBinaryExpression.OperatorType == ExpressionType.Equal) { @@ -331,10 +519,94 @@ private SqlBinaryExpression VisitSqlBinaryExpression(SqlBinaryExpression sqlBina } _isNullable = leftNullable || rightNullable; + _canOptimize = canOptimize; return sqlBinaryExpression.Update(newLeft, newRight); } + protected override Expression VisitSqlConstant(SqlConstantExpression sqlConstantExpression) + { + _isNullable = sqlConstantExpression.Value == null; + + return sqlConstantExpression; + } + + protected override Expression VisitSqlFragment(SqlFragmentExpression sqlFragmentExpression) + => sqlFragmentExpression; + + protected override Expression VisitSqlFunction(SqlFunctionExpression sqlFunctionExpression) + { + var canOptimize = _canOptimize; + _canOptimize = false; + + var newInstance = (SqlExpression)Visit(sqlFunctionExpression.Instance); + var newArguments = new SqlExpression[sqlFunctionExpression.Arguments.Count]; + for (var i = 0; i < newArguments.Length; i++) + { + newArguments[i] = (SqlExpression)Visit(sqlFunctionExpression.Arguments[i]); + } + + _canOptimize = canOptimize; + + // TODO: #18555 + _isNullable = true; + + return sqlFunctionExpression.Update(newInstance, newArguments); + } + + protected override Expression VisitSqlParameter(SqlParameterExpression sqlParameterExpression) + { + // at this point we assume every parameter is nullable, we will filter out the non-nullable ones once we know the actual values + _isNullable = true; + + return sqlParameterExpression; + } + + protected override Expression VisitSqlUnary(SqlUnaryExpression sqlCastExpression) + { + _isNullable = false; + + var canOptimize = _canOptimize; + _canOptimize = false; + + var newOperand = (SqlExpression)Visit(sqlCastExpression.Operand); + + // result of IsNull/IsNotNull can never be null + if (sqlCastExpression.OperatorType == ExpressionType.Equal + || sqlCastExpression.OperatorType == ExpressionType.NotEqual) + { + _isNullable = false; + } + + _canOptimize = canOptimize; + + return sqlCastExpression.Update(newOperand); + } + + protected override Expression VisitSubSelect(ScalarSubqueryExpression scalarSubqueryExpression) + { + var canOptimize = _canOptimize; + _canOptimize = false; + var subquery = (SelectExpression)Visit(scalarSubqueryExpression.Subquery); + _canOptimize = canOptimize; + + return scalarSubqueryExpression.Update(subquery); + } + + protected override Expression VisitTable(TableExpression tableExpression) + => tableExpression; + + protected override Expression VisitUnion(UnionExpression unionExpression) + { + var canOptimize = _canOptimize; + _canOptimize = false; + var source1 = (SelectExpression)Visit(unionExpression.Source1); + var source2 = (SelectExpression)Visit(unionExpression.Source2); + _canOptimize = canOptimize; + + return unionExpression.Update(source1, source2); + } + private List FindNonNullableColumns(SqlExpression sqlExpression) { var result = new List(); diff --git a/src/EFCore.Relational/Query/Internal/ParameterValueBasedSelectExpressionOptimizer.cs b/src/EFCore.Relational/Query/Internal/ParameterValueBasedSelectExpressionOptimizer.cs index 2763811d2d9..35069bcaff3 100644 --- a/src/EFCore.Relational/Query/Internal/ParameterValueBasedSelectExpressionOptimizer.cs +++ b/src/EFCore.Relational/Query/Internal/ParameterValueBasedSelectExpressionOptimizer.cs @@ -80,46 +80,49 @@ public ParameterNullabilityBasedSqlExpressionOptimizingExpressionVisitor( protected override Expression VisitExtension(Expression extensionExpression) { - if (extensionExpression is SelectExpression selectExpression) + // workaround for issue #18492 + var newExpression = base.VisitExtension(extensionExpression); + if (newExpression is SelectExpression newSelectExpression) { - var newSelectExpression = (SelectExpression)base.VisitExtension(extensionExpression); - - // if predicate is optimized to true, we can simply remove it - var newPredicate = newSelectExpression.Predicate is SqlConstantExpression newSelectPredicateConstant - && !(selectExpression.Predicate is SqlConstantExpression) - ? (bool)newSelectPredicateConstant.Value - ? null - : SqlExpressionFactory.Equal( - newSelectPredicateConstant, - SqlExpressionFactory.Constant(true, newSelectPredicateConstant.TypeMapping)) - : newSelectExpression.Predicate; - - var newHaving = newSelectExpression.Having is SqlConstantExpression newSelectHavingConstant - && !(selectExpression.Having is SqlConstantExpression) - ? (bool)newSelectHavingConstant.Value - ? null - : SqlExpressionFactory.Equal( - newSelectHavingConstant, - SqlExpressionFactory.Constant(true, newSelectHavingConstant.TypeMapping)) - : newSelectExpression.Having; - - return !ReferenceEquals(newPredicate, newSelectExpression.Predicate) - || !ReferenceEquals(newHaving, newSelectExpression.Having) - ? newSelectExpression.Update( - newSelectExpression.Projection.ToList(), - newSelectExpression.Tables.ToList(), - newPredicate, - newSelectExpression.GroupBy.ToList(), - newHaving, - newSelectExpression.Orderings.ToList(), - newSelectExpression.Limit, - newSelectExpression.Offset, - newSelectExpression.IsDistinct, - newSelectExpression.Alias) - : newSelectExpression; + var changed = false; + var newPredicate = newSelectExpression.Predicate; + var newHaving = newSelectExpression.Having; + if (newSelectExpression.Predicate is SqlConstantExpression predicateConstantExpression + && predicateConstantExpression.Value is bool predicateBoolValue + && !predicateBoolValue) + { + changed = true; + newPredicate = SqlExpressionFactory.Equal( + predicateConstantExpression, + SqlExpressionFactory.Constant(true, predicateConstantExpression.TypeMapping)); + } + + if (newSelectExpression.Having is SqlConstantExpression havingConstantExpression + && havingConstantExpression.Value is bool havingBoolValue + && !havingBoolValue) + { + changed = true; + newHaving = SqlExpressionFactory.Equal( + havingConstantExpression, + SqlExpressionFactory.Constant(true, havingConstantExpression.TypeMapping)); + } + + return changed + ? newSelectExpression.Update( + newSelectExpression.Projection.ToList(), + newSelectExpression.Tables.ToList(), + newPredicate, + newSelectExpression.GroupBy.ToList(), + newHaving, + newSelectExpression.Orderings.ToList(), + newSelectExpression.Limit, + newSelectExpression.Offset, + newSelectExpression.IsDistinct, + newSelectExpression.Alias) + : newSelectExpression; } - return base.VisitExtension(extensionExpression); + return newExpression; } protected override Expression VisitSqlUnaryExpression(SqlUnaryExpression sqlUnaryExpression) @@ -142,6 +145,33 @@ protected override Expression VisitSqlUnaryExpression(SqlUnaryExpression sqlUnar return result; } + + protected override Expression VisitSqlBinaryExpression(SqlBinaryExpression sqlBinaryExpression) + { + var result = base.VisitSqlBinaryExpression(sqlBinaryExpression); + if (result is SqlBinaryExpression sqlBinaryResult) + { + var leftNullParameter = sqlBinaryResult.Left is SqlParameterExpression leftParameter + && _parametersValues[leftParameter.Name] == null; + + var rightNullParameter = sqlBinaryResult.Right is SqlParameterExpression rightParameter + && _parametersValues[rightParameter.Name] == null; + + if ((sqlBinaryResult.OperatorType == ExpressionType.Equal || sqlBinaryResult.OperatorType == ExpressionType.NotEqual) + && (leftNullParameter || rightNullParameter)) + { + return SimplifyNullComparisonExpression( + sqlBinaryResult.OperatorType, + sqlBinaryResult.Left, + sqlBinaryResult.Right, + leftNullParameter, + rightNullParameter, + sqlBinaryResult.TypeMapping); + } + } + + return result; + } } private class InExpressionValuesExpandingExpressionVisitor : ExpressionVisitor diff --git a/src/EFCore.Relational/Query/Internal/SqlExpressionOptimizingExpressionVisitor.cs b/src/EFCore.Relational/Query/Internal/SqlExpressionOptimizingExpressionVisitor.cs index 7c33b1ba8e9..294d9f5f9d9 100644 --- a/src/EFCore.Relational/Query/Internal/SqlExpressionOptimizingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Internal/SqlExpressionOptimizingExpressionVisitor.cs @@ -1,6 +1,8 @@ // 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; using System.Linq.Expressions; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; using Microsoft.EntityFrameworkCore.Storage; @@ -44,222 +46,444 @@ protected override Expression VisitExtension(Expression extensionExpression) { SqlUnaryExpression sqlUnaryExpression => VisitSqlUnaryExpression(sqlUnaryExpression), SqlBinaryExpression sqlBinaryExpression => VisitSqlBinaryExpression(sqlBinaryExpression), + SelectExpression selectExpression => VisitSelectExpression(selectExpression), _ => base.VisitExtension(extensionExpression), }; - protected virtual Expression VisitSqlUnaryExpression(SqlUnaryExpression sqlUnaryExpression) + private Expression VisitSelectExpression(SelectExpression selectExpression) { - switch (sqlUnaryExpression.OperatorType) + var newExpression = base.VisitExtension(selectExpression); + + // if predicate is optimized to true, we can simply remove it + if (newExpression is SelectExpression newSelectExpression) { - case ExpressionType.Not: - return VisitNot(sqlUnaryExpression); + var changed = false; + var newPredicate = newSelectExpression.Predicate; + var newHaving = newSelectExpression.Having; + if (newSelectExpression.Predicate is SqlConstantExpression predicateConstantExpression + && predicateConstantExpression.Value is bool predicateBoolValue + && predicateBoolValue) + { + newPredicate = null; + changed = true; + } - case ExpressionType.Equal: - switch (sqlUnaryExpression.Operand) - { - case SqlConstantExpression constantOperand: - return SqlExpressionFactory.Constant(constantOperand.Value == null, sqlUnaryExpression.TypeMapping); + if (newSelectExpression.Having is SqlConstantExpression havingConstantExpression + && havingConstantExpression.Value is bool havingBoolValue + && havingBoolValue) + { + newHaving = null; + changed = true; + } - case ColumnExpression columnOperand - when !columnOperand.IsNullable: - return SqlExpressionFactory.Constant(false, sqlUnaryExpression.TypeMapping); + return changed + ? newSelectExpression.Update( + newSelectExpression.Projection.ToList(), + newSelectExpression.Tables.ToList(), + newPredicate, + newSelectExpression.GroupBy.ToList(), + newHaving, + newSelectExpression.Orderings.ToList(), + newSelectExpression.Limit, + newSelectExpression.Offset, + newSelectExpression.IsDistinct, + newSelectExpression.Alias) + : newSelectExpression; + } - case SqlUnaryExpression sqlUnaryOperand - when sqlUnaryOperand.OperatorType == ExpressionType.Convert - || sqlUnaryOperand.OperatorType == ExpressionType.Not - || sqlUnaryOperand.OperatorType == ExpressionType.Negate: - return (SqlExpression)Visit(SqlExpressionFactory.IsNull(sqlUnaryOperand.Operand)); + return newExpression; + } - case SqlBinaryExpression sqlBinaryOperand: - var newLeft = (SqlExpression)Visit(SqlExpressionFactory.IsNull(sqlBinaryOperand.Left)); - var newRight = (SqlExpression)Visit(SqlExpressionFactory.IsNull(sqlBinaryOperand.Right)); - - return sqlBinaryOperand.OperatorType == ExpressionType.Coalesce - ? SimplifyLogicalSqlBinaryExpression( - ExpressionType.AndAlso, newLeft, newRight, sqlBinaryOperand.TypeMapping) - : SimplifyLogicalSqlBinaryExpression( - ExpressionType.OrElse, newLeft, newRight, sqlBinaryOperand.TypeMapping); - } + protected virtual Expression VisitSqlUnaryExpression(SqlUnaryExpression sqlUnaryExpression) + { + var newOperand = (SqlExpression)Visit(sqlUnaryExpression.Operand); + + return SimplifyUnaryExpression( + sqlUnaryExpression.OperatorType, + newOperand, + sqlUnaryExpression.Type, + sqlUnaryExpression.TypeMapping); + } + private SqlExpression SimplifyUnaryExpression( + ExpressionType operatorType, + SqlExpression operand, + Type type, + RelationalTypeMapping typeMapping) + { + switch (operatorType) + { + case ExpressionType.Not: + switch (operand) + { + // !(true) -> false + // !(false) -> true + case SqlConstantExpression constantOperand + when constantOperand.Value is bool value: + { + return SqlExpressionFactory.Constant(!value, typeMapping); + } + + case InExpression inOperand: + return inOperand.Negate(); + + case SqlUnaryExpression unaryOperand: + switch (unaryOperand.OperatorType) + { + // !(!a) -> a + case ExpressionType.Not: + return unaryOperand.Operand; + + //!(a IS NULL) -> a IS NOT NULL + case ExpressionType.Equal: + return SqlExpressionFactory.IsNotNull(unaryOperand.Operand); + + //!(a IS NOT NULL) -> a IS NULL + case ExpressionType.NotEqual: + return SqlExpressionFactory.IsNull(unaryOperand.Operand); + } + break; + + case SqlBinaryExpression binaryOperand: + { + // De Morgan's + if (binaryOperand.OperatorType == ExpressionType.AndAlso + || binaryOperand.OperatorType == ExpressionType.OrElse) + { + var newLeft = SimplifyUnaryExpression(ExpressionType.Not, binaryOperand.Left, type, typeMapping); + var newRight = SimplifyUnaryExpression(ExpressionType.Not, binaryOperand.Right, type, typeMapping); + + return SimplifyLogicalSqlBinaryExpression( + binaryOperand.OperatorType == ExpressionType.AndAlso + ? ExpressionType.OrElse + : ExpressionType.AndAlso, + newLeft, + newRight, + binaryOperand.TypeMapping); + } + + // those optimizations are only valid in 2-value logic + // they are safe to do here because if we apply null semantics + // because null semantics removes possibility of nulls in the tree when the comparison is wrapped around NOT + if (!_useRelationalNulls && TryNegate(binaryOperand.OperatorType, out var negated)) + { + return SimplifyBinaryExpression( + negated, + binaryOperand.Left, + binaryOperand.Right, + binaryOperand.TypeMapping); + } + } + break; + } break; + case ExpressionType.Equal: case ExpressionType.NotEqual: - switch (sqlUnaryExpression.Operand) + return SimplifyNullNotNullExpression( + operatorType, + operand, + type, + typeMapping); + } + + return SqlExpressionFactory.MakeUnary(operatorType, operand, type, typeMapping); + } + + private SqlExpression SimplifyNullNotNullExpression( + ExpressionType operatorType, + SqlExpression operand, + Type type, + RelationalTypeMapping typeMapping) + { + switch (operatorType) + { + case ExpressionType.Equal: + case ExpressionType.NotEqual: + switch (operand) { case SqlConstantExpression constantOperand: - return SqlExpressionFactory.Constant(constantOperand.Value != null, sqlUnaryExpression.TypeMapping); + return SqlExpressionFactory.Constant( + operatorType == ExpressionType.Equal + ? constantOperand.Value == null + : constantOperand.Value != null, + typeMapping); case ColumnExpression columnOperand when !columnOperand.IsNullable: - return SqlExpressionFactory.Constant(true, sqlUnaryExpression.TypeMapping); - - case SqlUnaryExpression sqlUnaryOperand - when sqlUnaryOperand.OperatorType == ExpressionType.Convert - || sqlUnaryOperand.OperatorType == ExpressionType.Not - || sqlUnaryOperand.OperatorType == ExpressionType.Negate: - return (SqlExpression)Visit(SqlExpressionFactory.IsNotNull(sqlUnaryOperand.Operand)); + return SqlExpressionFactory.Constant(operatorType == ExpressionType.NotEqual, typeMapping); + + case SqlUnaryExpression sqlUnaryOperand: + if (sqlUnaryOperand.OperatorType == ExpressionType.Convert + || sqlUnaryOperand.OperatorType == ExpressionType.Not + || sqlUnaryOperand.OperatorType == ExpressionType.Negate) + { + // op(a) is null -> a is null + // op(a) is not null -> a is not null + return SimplifyNullNotNullExpression(operatorType, sqlUnaryOperand.Operand, type, typeMapping); + } + + if (sqlUnaryOperand.OperatorType == ExpressionType.Equal + || sqlUnaryOperand.OperatorType == ExpressionType.NotEqual) + { + // (a is null) is null -> false + // (a is not null) is null -> false + // (a is null) is not null -> true + // (a is not null) is not null -> true + return SqlExpressionFactory.Constant(operatorType == ExpressionType.NotEqual, typeMapping); + } + break; case SqlBinaryExpression sqlBinaryOperand: - var newLeft = (SqlExpression)Visit(SqlExpressionFactory.IsNotNull(sqlBinaryOperand.Left)); - var newRight = (SqlExpression)Visit(SqlExpressionFactory.IsNotNull(sqlBinaryOperand.Right)); - - return sqlBinaryOperand.OperatorType == ExpressionType.Coalesce - ? SimplifyLogicalSqlBinaryExpression(ExpressionType.OrElse, newLeft, newRight, sqlBinaryOperand.TypeMapping) - : SimplifyLogicalSqlBinaryExpression( - ExpressionType.AndAlso, newLeft, newRight, sqlBinaryOperand.TypeMapping); + // in general: + // binaryOp(a, b) == null -> a == null || b == null + // binaryOp(a, b) != null -> a != null && b != null + // for coalesce: + // (a ?? b) == null -> a == null && b == null + // (a ?? b) != null -> a != null || b != null + // for AndAlso, OrElse, And, Or we can't do this optimization + // we could do something like this, but it seems too complicated: + // (a && b) == null -> a == null && b != 0 || a != 0 && b == null + if (sqlBinaryOperand.OperatorType != ExpressionType.AndAlso + && sqlBinaryOperand.OperatorType != ExpressionType.OrElse + && sqlBinaryOperand.OperatorType != ExpressionType.And + && sqlBinaryOperand.OperatorType != ExpressionType.Or) + { + var newLeft = SimplifyNullNotNullExpression(operatorType, sqlBinaryOperand.Left, typeof(bool), typeMapping); + var newRight = SimplifyNullNotNullExpression(operatorType, sqlBinaryOperand.Right, typeof(bool), typeMapping); + + return sqlBinaryOperand.OperatorType == ExpressionType.Coalesce + ? SimplifyLogicalSqlBinaryExpression( + operatorType == ExpressionType.Equal + ? ExpressionType.AndAlso + : ExpressionType.OrElse, + newLeft, + newRight, + typeMapping) + : SimplifyLogicalSqlBinaryExpression( + operatorType == ExpressionType.Equal + ? ExpressionType.OrElse + : ExpressionType.AndAlso, + newLeft, + newRight, + typeMapping); + } + break; } - break; } - var newOperand = (SqlExpression)Visit(sqlUnaryExpression.Operand); + return SqlExpressionFactory.MakeUnary(operatorType, operand, type, typeMapping); + } - return sqlUnaryExpression.Update(newOperand); + protected virtual Expression VisitSqlBinaryExpression(SqlBinaryExpression sqlBinaryExpression) + { + var newLeft = (SqlExpression)Visit(sqlBinaryExpression.Left); + var newRight = (SqlExpression)Visit(sqlBinaryExpression.Right); + + return SimplifyBinaryExpression( + sqlBinaryExpression.OperatorType, + newLeft, + newRight, + sqlBinaryExpression.TypeMapping); } - private Expression VisitNot(SqlUnaryExpression sqlUnaryExpression) + private SqlExpression SimplifyBinaryExpression( + ExpressionType operatorType, + SqlExpression left, + SqlExpression right, + RelationalTypeMapping typeMapping) { - // !(true) -> false - // !(false) -> true - if (sqlUnaryExpression.Operand is SqlConstantExpression innerConstantBool - && innerConstantBool.Value is bool value) + switch (operatorType) { - return SqlExpressionFactory.Constant(!value, sqlUnaryExpression.TypeMapping); - } + case ExpressionType.AndAlso: + case ExpressionType.OrElse: + var leftUnary = left as SqlUnaryExpression; + var rightUnary = right as SqlUnaryExpression; + if (leftUnary != null + && rightUnary != null + && (leftUnary.OperatorType == ExpressionType.Equal || leftUnary.OperatorType == ExpressionType.NotEqual) + && (rightUnary.OperatorType == ExpressionType.Equal || rightUnary.OperatorType == ExpressionType.NotEqual) + && leftUnary.Operand.Equals(rightUnary.Operand)) + { + // a is null || a is null -> a is null + // a is not null || a is not null -> a is not null + // a is null && a is null -> a is null + // a is not null && a is not null -> a is not null + // a is null || a is not null -> true + // a is null && a is not null -> false + return leftUnary.OperatorType == rightUnary.OperatorType + ? (SqlExpression)leftUnary + : SqlExpressionFactory.Constant(operatorType == ExpressionType.OrElse, typeMapping); + } - if (sqlUnaryExpression.Operand is InExpression inExpression) - { - return Visit(inExpression.Negate()); - } + return SimplifyLogicalSqlBinaryExpression( + operatorType, + left, + right, + typeMapping); - if (sqlUnaryExpression.Operand is SqlUnaryExpression innerUnary) - { - // !(!a) -> a - if (innerUnary.OperatorType == ExpressionType.Not) - { - return Visit(innerUnary.Operand); - } + case ExpressionType.Equal: + case ExpressionType.NotEqual: + var leftConstant = left as SqlConstantExpression; + var rightConstant = right as SqlConstantExpression; + var leftNullConstant = leftConstant != null && leftConstant.Value == null; + var rightNullConstant = rightConstant != null && rightConstant.Value == null; + if (leftNullConstant || rightNullConstant) + { + return SimplifyNullComparisonExpression( + operatorType, + left, + right, + leftNullConstant, + rightNullConstant, + typeMapping); + } - if (innerUnary.OperatorType == ExpressionType.Equal) - { - //!(a IS NULL) -> a IS NOT NULL - return Visit(SqlExpressionFactory.IsNotNull(innerUnary.Operand)); - } + var leftBoolConstant = left.Type == typeof(bool) ? leftConstant : null; + var rightBoolConstant = right.Type == typeof(bool) ? rightConstant : null; + if (leftBoolConstant != null || rightBoolConstant != null) + { + return SimplifyBoolConstantComparisonExpression( + operatorType, + left, + right, + leftBoolConstant, + rightBoolConstant, + typeMapping); + } - //!(a IS NOT NULL) -> a IS NULL - if (innerUnary.OperatorType == ExpressionType.NotEqual) - { - return Visit(SqlExpressionFactory.IsNull(innerUnary.Operand)); - } + // only works when a is not nullable + // a == a -> true + // a != a -> false + if ((left is LikeExpression + || left is ColumnExpression columnExpression && !columnExpression.IsNullable) + && left.Equals(right)) + { + return SqlExpressionFactory.Constant(operatorType == ExpressionType.Equal, typeMapping); + } + + break; } - if (sqlUnaryExpression.Operand is SqlBinaryExpression innerBinary) + return SqlExpressionFactory.MakeBinary(operatorType, left, right, typeMapping); + } + + protected virtual SqlExpression SimplifyNullComparisonExpression( + ExpressionType operatorType, + SqlExpression left, + SqlExpression right, + bool leftNull, + bool rightNull, + RelationalTypeMapping typeMapping) + { + if ((operatorType == ExpressionType.Equal || operatorType == ExpressionType.NotEqual) + && (leftNull || rightNull)) { - // De Morgan's - if (innerBinary.OperatorType == ExpressionType.AndAlso - || innerBinary.OperatorType == ExpressionType.OrElse) + if (leftNull && rightNull) { - var newLeft = (SqlExpression)Visit(SqlExpressionFactory.Not(innerBinary.Left)); - var newRight = (SqlExpression)Visit(SqlExpressionFactory.Not(innerBinary.Right)); + return SqlExpressionFactory.Constant(operatorType == ExpressionType.Equal, typeMapping); + } - return SimplifyLogicalSqlBinaryExpression( - innerBinary.OperatorType == ExpressionType.AndAlso - ? ExpressionType.OrElse - : ExpressionType.AndAlso, - newLeft, - newRight, - innerBinary.TypeMapping); + if (leftNull) + { + return SimplifyNullNotNullExpression(operatorType, right, typeof(bool), typeMapping); } - // those optimizations are only valid in 2-value logic - // they are safe to do here because null semantics removes possibility of nulls in the tree - // however if we decide to do "partial" null semantics (that doesn't distinguish between NULL and FALSE, e.g. for predicates) - // we need to be extra careful here - if (!_useRelationalNulls - && TryNegate(innerBinary.OperatorType, out var negated)) + if (rightNull) { - return Visit( - SqlExpressionFactory.MakeBinary( - negated, - innerBinary.Left, - innerBinary.Right, - innerBinary.TypeMapping)); + return SimplifyNullNotNullExpression(operatorType, left, typeof(bool), typeMapping); } } - var newOperand = (SqlExpression)Visit(sqlUnaryExpression.Operand); - - return sqlUnaryExpression.Update(newOperand); + return SqlExpressionFactory.MakeBinary(operatorType, left, right, typeMapping); } - private Expression VisitSqlBinaryExpression(SqlBinaryExpression sqlBinaryExpression) + private SqlExpression SimplifyBoolConstantComparisonExpression( + ExpressionType operatorType, + SqlExpression left, + SqlExpression right, + SqlConstantExpression leftBoolConstant, + SqlConstantExpression rightBoolConstant, + RelationalTypeMapping typeMapping) { - var newLeft = (SqlExpression)Visit(sqlBinaryExpression.Left); - var newRight = (SqlExpression)Visit(sqlBinaryExpression.Right); + if (leftBoolConstant != null && rightBoolConstant != null) + { + // potential optimization: + // we can't do it on SqlServer because it reverts search conditions back to values + // and we run this visitor after search condition visitor + //return operatorType == ExpressionType.Equal + // ? SqlExpressionFactory.Constant((bool)leftBoolConstant.Value == (bool)rightBoolConstant.Value, typeMapping) + // : SqlExpressionFactory.Constant((bool)leftBoolConstant.Value != (bool)rightBoolConstant.Value, typeMapping); + return SqlExpressionFactory.MakeBinary(operatorType, left, right, typeMapping); + } - if (sqlBinaryExpression.OperatorType == ExpressionType.AndAlso - || sqlBinaryExpression.OperatorType == ExpressionType.OrElse) + if (rightBoolConstant != null + && CanOptimize(left)) { - return SimplifyLogicalSqlBinaryExpression( - sqlBinaryExpression.OperatorType, - newLeft, - newRight, - sqlBinaryExpression.TypeMapping); + // a == true -> a + // a == false -> !a + // a != true -> !a + // a != false -> a + // only correct when f(x) can't be null + return operatorType == ExpressionType.Equal + ? (bool)rightBoolConstant.Value + ? left + : SimplifyUnaryExpression(ExpressionType.Not, left, typeof(bool), typeMapping) + : (bool)rightBoolConstant.Value + ? SimplifyUnaryExpression(ExpressionType.Not, left, typeof(bool), typeMapping) + : left; } - // those optimizations are only valid in 2-value logic - // they are safe to do here because null semantics removes possibility of nulls in the tree - // however if we decide to do "partial" null semantics (that doesn't distinguish between NULL and FALSE, e.g. for predicates) - // we need to be extra careful here - if (!_useRelationalNulls - && (sqlBinaryExpression.OperatorType == ExpressionType.Equal - || sqlBinaryExpression.OperatorType == ExpressionType.NotEqual)) + if (leftBoolConstant != null + && CanOptimize(right)) { - // op(a, b) == true -> op(a, b) - // op(a, b) != false -> op(a, b) - // op(a, b) == false -> !op(a, b) - // op(a, b) != true -> !op(a, b) - var constant = sqlBinaryExpression.Left as SqlConstantExpression ?? sqlBinaryExpression.Right as SqlConstantExpression; - var binary = sqlBinaryExpression.Left as SqlBinaryExpression ?? sqlBinaryExpression.Right as SqlBinaryExpression; - if (constant != null - && binary != null - && TryNegate(binary.OperatorType, out var negated)) - { - return (bool)constant.Value == (sqlBinaryExpression.OperatorType == ExpressionType.Equal) - ? binary - : SqlExpressionFactory.MakeBinary( - negated, - sqlBinaryExpression.Left, - sqlBinaryExpression.Right, - sqlBinaryExpression.TypeMapping); - } + // true == a -> a + // false == a -> !a + // true != a -> !a + // false != a -> a + // only correct when a can't be null + return operatorType == ExpressionType.Equal + ? (bool)leftBoolConstant.Value + ? right + : SimplifyUnaryExpression(ExpressionType.Not, right, typeof(bool), typeMapping) + : (bool)leftBoolConstant.Value + ? SimplifyUnaryExpression(ExpressionType.Not, right, typeof(bool), typeMapping) + : right; } - return sqlBinaryExpression.Update(newLeft, newRight); + return SqlExpressionFactory.MakeBinary(operatorType, left, right, typeMapping); + + static bool CanOptimize(SqlExpression operand) + => operand is LikeExpression + || (operand is SqlUnaryExpression sqlUnary + && (sqlUnary.OperatorType == ExpressionType.Equal + || sqlUnary.OperatorType == ExpressionType.NotEqual + // TODO: #18689 + /*|| sqlUnary.OperatorType == ExpressionType.Not*/)); } private SqlExpression SimplifyLogicalSqlBinaryExpression( ExpressionType operatorType, - SqlExpression newLeft, - SqlExpression newRight, + SqlExpression left, + SqlExpression right, RelationalTypeMapping typeMapping) { // true && a -> a // true || a -> true // false && a -> false // false || a -> a - if (newLeft is SqlConstantExpression newLeftConstant) + if (left is SqlConstantExpression newLeftConstant) { return operatorType == ExpressionType.AndAlso ? (bool)newLeftConstant.Value - ? newRight + ? right : newLeftConstant : (bool)newLeftConstant.Value ? newLeftConstant - : newRight; + : right; } - - if (newRight is SqlConstantExpression newRightConstant) + else if (right is SqlConstantExpression newRightConstant) { // a && true -> a // a || true -> true @@ -267,14 +491,14 @@ private SqlExpression SimplifyLogicalSqlBinaryExpression( // a || false -> a return operatorType == ExpressionType.AndAlso ? (bool)newRightConstant.Value - ? newLeft + ? left : newRightConstant : (bool)newRightConstant.Value ? newRightConstant - : newLeft; + : left; } - return SqlExpressionFactory.MakeBinary(operatorType, newLeft, newRight, typeMapping); + return SqlExpressionFactory.MakeBinary(operatorType, left, right, typeMapping); } } } diff --git a/src/EFCore.Relational/Query/RelationalQueryTranslationPostprocessor.cs b/src/EFCore.Relational/Query/RelationalQueryTranslationPostprocessor.cs index 3fd24558073..23f171c1fb5 100644 --- a/src/EFCore.Relational/Query/RelationalQueryTranslationPostprocessor.cs +++ b/src/EFCore.Relational/Query/RelationalQueryTranslationPostprocessor.cs @@ -43,7 +43,6 @@ public override Expression Process(Expression query) } query = OptimizeSqlExpression(query); - query = new NullComparisonTransformingExpressionVisitor().Visit(query); return query; } diff --git a/src/EFCore.Relational/Query/SqlExpressionVisitor.cs b/src/EFCore.Relational/Query/SqlExpressionVisitor.cs index 6db56f75572..c034f4e0f14 100644 --- a/src/EFCore.Relational/Query/SqlExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/SqlExpressionVisitor.cs @@ -18,14 +18,14 @@ protected override Expression VisitExtension(Expression extensionExpression) case ColumnExpression columnExpression: return VisitColumn(columnExpression); - case CrossJoinExpression crossJoinExpression: - return VisitCrossJoin(crossJoinExpression); - case CrossApplyExpression crossApplyExpression: return VisitCrossApply(crossApplyExpression); - case OuterApplyExpression outerApplyExpression: - return VisitOuterApply(outerApplyExpression); + case CrossJoinExpression crossJoinExpression: + return VisitCrossJoin(crossJoinExpression); + + case ExceptExpression exceptExpression: + return VisitExcept(exceptExpression); case ExistsExpression existsExpression: return VisitExists(existsExpression); @@ -36,6 +36,9 @@ protected override Expression VisitExtension(Expression extensionExpression) case InExpression inExpression: return VisitIn(inExpression); + case IntersectExpression intersectExpression: + return VisitIntersect(intersectExpression); + case InnerJoinExpression innerJoinExpression: return VisitInnerJoin(innerJoinExpression); @@ -48,6 +51,9 @@ protected override Expression VisitExtension(Expression extensionExpression) case OrderingExpression orderingExpression: return VisitOrdering(orderingExpression); + case OuterApplyExpression outerApplyExpression: + return VisitOuterApply(outerApplyExpression); + case ProjectionExpression projectionExpression: return VisitProjection(projectionExpression); @@ -81,12 +87,6 @@ protected override Expression VisitExtension(Expression extensionExpression) case TableExpression tableExpression: return VisitTable(tableExpression); - case ExceptExpression exceptExpression: - return VisitExcept(exceptExpression); - - case IntersectExpression intersectExpression: - return VisitIntersect(intersectExpression); - case UnionExpression unionExpression: return VisitUnion(unionExpression); } @@ -94,31 +94,31 @@ protected override Expression VisitExtension(Expression extensionExpression) return base.VisitExtension(extensionExpression); } - protected abstract Expression VisitRowNumber(RowNumberExpression rowNumberExpression); + protected abstract Expression VisitCase(CaseExpression caseExpression); + protected abstract Expression VisitColumn(ColumnExpression columnExpression); + protected abstract Expression VisitCrossApply(CrossApplyExpression crossApplyExpression); + protected abstract Expression VisitCrossJoin(CrossJoinExpression crossJoinExpression); protected abstract Expression VisitExcept(ExceptExpression exceptExpression); - protected abstract Expression VisitIntersect(IntersectExpression intersectExpression); - protected abstract Expression VisitUnion(UnionExpression unionExpression); protected abstract Expression VisitExists(ExistsExpression existsExpression); - protected abstract Expression VisitIn(InExpression inExpression); - protected abstract Expression VisitCrossJoin(CrossJoinExpression crossJoinExpression); - protected abstract Expression VisitCrossApply(CrossApplyExpression crossApplyExpression); - protected abstract Expression VisitOuterApply(OuterApplyExpression outerApplyExpression); protected abstract Expression VisitFromSql(FromSqlExpression fromSqlExpression); + protected abstract Expression VisitIn(InExpression inExpression); + protected abstract Expression VisitIntersect(IntersectExpression intersectExpression); + protected abstract Expression VisitLike(LikeExpression likeExpression); protected abstract Expression VisitInnerJoin(InnerJoinExpression innerJoinExpression); protected abstract Expression VisitLeftJoin(LeftJoinExpression leftJoinExpression); - protected abstract Expression VisitProjection(ProjectionExpression projectionExpression); - protected abstract Expression VisitCase(CaseExpression caseExpression); - protected abstract Expression VisitSqlUnary(SqlUnaryExpression sqlCastExpression); - protected abstract Expression VisitSqlFunction(SqlFunctionExpression sqlFunctionExpression); - protected abstract Expression VisitSqlFragment(SqlFragmentExpression sqlFragmentExpression); protected abstract Expression VisitOrdering(OrderingExpression orderingExpression); - protected abstract Expression VisitSqlParameter(SqlParameterExpression sqlParameterExpression); - protected abstract Expression VisitSqlBinary(SqlBinaryExpression sqlBinaryExpression); - protected abstract Expression VisitColumn(ColumnExpression columnExpression); + protected abstract Expression VisitOuterApply(OuterApplyExpression outerApplyExpression); + protected abstract Expression VisitProjection(ProjectionExpression projectionExpression); + protected abstract Expression VisitRowNumber(RowNumberExpression rowNumberExpression); protected abstract Expression VisitSelect(SelectExpression selectExpression); - protected abstract Expression VisitTable(TableExpression tableExpression); + protected abstract Expression VisitSqlBinary(SqlBinaryExpression sqlBinaryExpression); protected abstract Expression VisitSqlConstant(SqlConstantExpression sqlConstantExpression); - protected abstract Expression VisitLike(LikeExpression likeExpression); + protected abstract Expression VisitSqlFragment(SqlFragmentExpression sqlFragmentExpression); + protected abstract Expression VisitSqlFunction(SqlFunctionExpression sqlFunctionExpression); + protected abstract Expression VisitSqlParameter(SqlParameterExpression sqlParameterExpression); + protected abstract Expression VisitSqlUnary(SqlUnaryExpression sqlCastExpression); protected abstract Expression VisitSubSelect(ScalarSubqueryExpression scalarSubqueryExpression); + protected abstract Expression VisitTable(TableExpression tableExpression); + protected abstract Expression VisitUnion(UnionExpression unionExpression); } } diff --git a/src/EFCore.Relational/Query/SqlExpressions/SqlExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SqlExpression.cs index 7f8e1bdd2d6..57553c24164 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SqlExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SqlExpression.cs @@ -32,7 +32,8 @@ public override bool Equals(object obj) private bool Equals(SqlExpression sqlExpression) => Type == sqlExpression.Type - && TypeMapping?.Equals(sqlExpression.TypeMapping) == true; + && ((TypeMapping == null && sqlExpression.TypeMapping == null) + || TypeMapping?.Equals(sqlExpression.TypeMapping) == true); public override int GetHashCode() => HashCode.Combine(Type, TypeMapping); } diff --git a/src/EFCore.SqlServer/Query/Internal/SearchConditionConvertingExpressionVisitor.cs b/src/EFCore.SqlServer/Query/Internal/SearchConditionConvertingExpressionVisitor.cs index 9f91a7b4842..7736fbe01a3 100644 --- a/src/EFCore.SqlServer/Query/Internal/SearchConditionConvertingExpressionVisitor.cs +++ b/src/EFCore.SqlServer/Query/Internal/SearchConditionConvertingExpressionVisitor.cs @@ -253,9 +253,7 @@ protected override Expression VisitSqlConstant(SqlConstantExpression sqlConstant } protected override Expression VisitSqlFragment(SqlFragmentExpression sqlFragmentExpression) - { - return sqlFragmentExpression; - } + => sqlFragmentExpression; protected override Expression VisitSqlFunction(SqlFunctionExpression sqlFunctionExpression) { @@ -283,9 +281,7 @@ protected override Expression VisitSqlParameter(SqlParameterExpression sqlParame } protected override Expression VisitTable(TableExpression tableExpression) - { - return tableExpression; - } + => tableExpression; protected override Expression VisitProjection(ProjectionExpression projectionExpression) { diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryTranslationPostprocessor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryTranslationPostprocessor.cs index a81be171ec6..500cf13d63a 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryTranslationPostprocessor.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryTranslationPostprocessor.cs @@ -20,7 +20,6 @@ public override Expression Process(Expression query) { query = base.Process(query); query = new SearchConditionConvertingExpressionVisitor(SqlExpressionFactory).Visit(query); - query = OptimizeSqlExpression(query); return query; } diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/SimpleQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/SimpleQueryCosmosTest.cs index 8d53560bfc7..0cc86a724d2 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/SimpleQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/SimpleQueryCosmosTest.cs @@ -4151,6 +4151,12 @@ public override Task Collection_FirstOrDefault_with_nullable_unsigned_int_column return base.Collection_FirstOrDefault_with_nullable_unsigned_int_column(isAsync); } + [ConditionalTheory(Skip = "Issue #17246")] + public override Task IsNullOrWhiteSpace_in_predicate_on_non_nullable_column(bool isAsync) + { + return base.IsNullOrWhiteSpace_in_predicate_on_non_nullable_column(isAsync); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.Functions.cs b/test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.Functions.cs index 181ce29d9f3..6016b2e3142 100644 --- a/test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.Functions.cs +++ b/test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.Functions.cs @@ -1308,6 +1308,15 @@ public virtual Task IsNullOrWhiteSpace_in_predicate(bool isAsync) entryCount: 60); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task IsNullOrWhiteSpace_in_predicate_on_non_nullable_column(bool isAsync) + { + return AssertQuery( + isAsync, + ss => ss.Set().Where(c => string.IsNullOrWhiteSpace(c.CustomerID))); + } + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task TrimStart_without_arguments_in_predicate(bool isAsync) diff --git a/test/EFCore.SqlServer.FunctionalTests/BuiltInDataTypesSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/BuiltInDataTypesSqlServerTest.cs index 5fda0678299..7bbb858d52b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/BuiltInDataTypesSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/BuiltInDataTypesSqlServerTest.cs @@ -49,7 +49,7 @@ var results AssertSql( @"SELECT [m].[Int] FROM [MappedNullableDataTypes] AS [m] -WHERE ([m].[TimeSpanAsTime] = '00:01:02') AND [m].[TimeSpanAsTime] IS NOT NULL"); +WHERE [m].[TimeSpanAsTime] = '00:01:02'"); } } @@ -89,7 +89,7 @@ var results SELECT [m].[Int] FROM [MappedNullableDataTypes] AS [m] -WHERE ([m].[TimeSpanAsTime] = @__timeSpan_0) AND [m].[TimeSpanAsTime] IS NOT NULL"); +WHERE [m].[TimeSpanAsTime] = @__timeSpan_0"); } } @@ -112,7 +112,7 @@ var results SELECT [m].[Int] FROM [MappedNullableDataTypes] AS [m] -WHERE (DATEDIFF(HOUR, [m].[TimeSpanAsTime], @__timeSpan_1) = 0) AND DATEDIFF(HOUR, [m].[TimeSpanAsTime], @__timeSpan_1) IS NOT NULL"); +WHERE DATEDIFF(HOUR, [m].[TimeSpanAsTime], @__timeSpan_1) = 0"); } } @@ -135,7 +135,7 @@ var results SELECT [m].[Int] FROM [MappedNullableDataTypes] AS [m] -WHERE (DATEDIFF(MINUTE, [m].[TimeSpanAsTime], @__timeSpan_1) = 0) AND DATEDIFF(MINUTE, [m].[TimeSpanAsTime], @__timeSpan_1) IS NOT NULL"); +WHERE DATEDIFF(MINUTE, [m].[TimeSpanAsTime], @__timeSpan_1) = 0"); } } @@ -158,7 +158,7 @@ var results SELECT [m].[Int] FROM [MappedNullableDataTypes] AS [m] -WHERE (DATEDIFF(SECOND, [m].[TimeSpanAsTime], @__timeSpan_1) = 0) AND DATEDIFF(SECOND, [m].[TimeSpanAsTime], @__timeSpan_1) IS NOT NULL"); +WHERE DATEDIFF(SECOND, [m].[TimeSpanAsTime], @__timeSpan_1) = 0"); } } @@ -181,7 +181,7 @@ var results SELECT [m].[Int] FROM [MappedNullableDataTypes] AS [m] -WHERE (DATEDIFF(MILLISECOND, [m].[TimeSpanAsTime], @__timeSpan_1) = 0) AND DATEDIFF(MILLISECOND, [m].[TimeSpanAsTime], @__timeSpan_1) IS NOT NULL"); +WHERE DATEDIFF(MILLISECOND, [m].[TimeSpanAsTime], @__timeSpan_1) = 0"); } } @@ -204,7 +204,7 @@ var results SELECT [m].[Int] FROM [MappedNullableDataTypes] AS [m] -WHERE (DATEDIFF(MICROSECOND, [m].[TimeSpanAsTime], @__timeSpan_1) = 0) AND DATEDIFF(MICROSECOND, [m].[TimeSpanAsTime], @__timeSpan_1) IS NOT NULL"); +WHERE DATEDIFF(MICROSECOND, [m].[TimeSpanAsTime], @__timeSpan_1) = 0"); } } @@ -227,7 +227,7 @@ var results SELECT [m].[Int] FROM [MappedNullableDataTypes] AS [m] -WHERE (DATEDIFF(NANOSECOND, [m].[TimeSpanAsTime], @__timeSpan_1) = 0) AND DATEDIFF(NANOSECOND, [m].[TimeSpanAsTime], @__timeSpan_1) IS NOT NULL"); +WHERE DATEDIFF(NANOSECOND, [m].[TimeSpanAsTime], @__timeSpan_1) = 0"); } } diff --git a/test/EFCore.SqlServer.FunctionalTests/LoadSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/LoadSqlServerTest.cs index c117847db41..fb2e41e13ab 100644 --- a/test/EFCore.SqlServer.FunctionalTests/LoadSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/LoadSqlServerTest.cs @@ -27,7 +27,7 @@ public override void Lazy_load_collection(EntityState state) SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override void Lazy_load_many_to_one_reference_to_principal(EntityState state) @@ -63,7 +63,7 @@ public override void Lazy_load_one_to_one_reference_to_dependent(EntityState sta SELECT [s].[Id], [s].[ParentId] FROM [Single] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override void Lazy_load_one_to_one_PK_to_PK_reference_to_principal(EntityState state) @@ -113,7 +113,7 @@ public override void Lazy_load_collection_not_found(EntityState state) SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override void Lazy_load_many_to_one_reference_to_principal_not_found(EntityState state) @@ -149,7 +149,7 @@ public override void Lazy_load_one_to_one_reference_to_dependent_not_found(Entit SELECT [s].[Id], [s].[ParentId] FROM [Single] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override void Lazy_load_collection_already_loaded(EntityState state, CascadeTiming cascadeDeleteTiming) @@ -228,7 +228,7 @@ public override void Lazy_load_one_to_one_reference_to_dependent_alternate_key(E SELECT [s].[Id], [s].[ParentId] FROM [SingleAk] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override void Lazy_load_many_to_one_reference_to_principal_null_FK_alternate_key(EntityState state) @@ -254,7 +254,7 @@ public override void Lazy_load_collection_shadow_fk(EntityState state) SELECT [c].[Id], [c].[ParentId] FROM [ChildShadowFk] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override void Lazy_load_many_to_one_reference_to_principal_shadow_fk(EntityState state) @@ -290,7 +290,7 @@ public override void Lazy_load_one_to_one_reference_to_dependent_shadow_fk(Entit SELECT [s].[Id], [s].[ParentId] FROM [SingleShadowFk] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override void Lazy_load_many_to_one_reference_to_principal_null_FK_shadow_fk(EntityState state) @@ -317,7 +317,7 @@ public override void Lazy_load_collection_composite_key(EntityState state) SELECT [c].[Id], [c].[ParentAlternateId], [c].[ParentId] FROM [ChildCompositeKey] AS [c] -WHERE (([c].[ParentAlternateId] = @__p_0) AND [c].[ParentAlternateId] IS NOT NULL) AND (([c].[ParentId] = @__p_1) AND [c].[ParentId] IS NOT NULL)"); +WHERE ([c].[ParentAlternateId] = @__p_0) AND ([c].[ParentId] = @__p_1)"); } public override void Lazy_load_many_to_one_reference_to_principal_composite_key(EntityState state) @@ -356,7 +356,7 @@ public override void Lazy_load_one_to_one_reference_to_dependent_composite_key(E SELECT [s].[Id], [s].[ParentAlternateId], [s].[ParentId] FROM [SingleCompositeKey] AS [s] -WHERE (([s].[ParentAlternateId] = @__p_0) AND [s].[ParentAlternateId] IS NOT NULL) AND (([s].[ParentId] = @__p_1) AND [s].[ParentId] IS NOT NULL)"); +WHERE ([s].[ParentAlternateId] = @__p_0) AND ([s].[ParentId] = @__p_1)"); } public override void Lazy_load_many_to_one_reference_to_principal_null_FK_composite_key(EntityState state) @@ -382,7 +382,7 @@ public override async Task Load_collection(EntityState state, bool async) SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal(EntityState state, bool async) @@ -418,7 +418,7 @@ public override async Task Load_one_to_one_reference_to_dependent(EntityState st SELECT [s].[Id], [s].[ParentId] FROM [Single] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override async Task Load_one_to_one_PK_to_PK_reference_to_principal(EntityState state, bool async) @@ -454,7 +454,7 @@ public override async Task Load_collection_using_Query(EntityState state, bool a SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal_using_Query(EntityState state, bool async) @@ -490,7 +490,7 @@ public override async Task Load_one_to_one_reference_to_dependent_using_Query(En SELECT TOP(2) [s].[Id], [s].[ParentId] FROM [Single] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override async Task Load_one_to_one_PK_to_PK_reference_to_principal_using_Query(EntityState state, bool async) @@ -560,7 +560,7 @@ public override async Task Load_collection_not_found(EntityState state, bool asy SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal_not_found(EntityState state, bool async) @@ -596,7 +596,7 @@ public override async Task Load_one_to_one_reference_to_dependent_not_found(Enti SELECT [s].[Id], [s].[ParentId] FROM [Single] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override async Task Load_collection_using_Query_not_found(EntityState state, bool async) @@ -608,7 +608,7 @@ public override async Task Load_collection_using_Query_not_found(EntityState sta SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal_using_Query_not_found(EntityState state, bool async) @@ -644,7 +644,7 @@ public override async Task Load_one_to_one_reference_to_dependent_using_Query_no SELECT TOP(2) [s].[Id], [s].[ParentId] FROM [Single] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override async Task Load_collection_already_loaded(EntityState state, bool async, CascadeTiming cascadeDeleteTiming) @@ -701,7 +701,7 @@ public override async Task Load_collection_using_Query_already_loaded( SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal_using_Query_already_loaded(EntityState state, bool async) @@ -738,7 +738,7 @@ public override async Task Load_one_to_one_reference_to_dependent_using_Query_al SELECT TOP(2) [s].[Id], [s].[ParentId] FROM [Single] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override async Task Load_one_to_one_PK_to_PK_reference_to_principal_using_Query_already_loaded(EntityState state, bool async) @@ -774,7 +774,7 @@ public override async Task Load_collection_untyped(EntityState state, bool async SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal_untyped(EntityState state, bool async) @@ -810,7 +810,7 @@ public override async Task Load_one_to_one_reference_to_dependent_untyped(Entity SELECT [s].[Id], [s].[ParentId] FROM [Single] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override async Task Load_collection_using_Query_untyped(EntityState state, bool async) @@ -822,7 +822,7 @@ public override async Task Load_collection_using_Query_untyped(EntityState state SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal_using_Query_untyped(EntityState state, bool async) @@ -858,7 +858,7 @@ public override async Task Load_one_to_one_reference_to_dependent_using_Query_un SELECT [s].[Id], [s].[ParentId] FROM [Single] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override async Task Load_collection_not_found_untyped(EntityState state, bool async) @@ -870,7 +870,7 @@ public override async Task Load_collection_not_found_untyped(EntityState state, SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal_not_found_untyped(EntityState state, bool async) @@ -906,7 +906,7 @@ public override async Task Load_one_to_one_reference_to_dependent_not_found_unty SELECT [s].[Id], [s].[ParentId] FROM [Single] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override async Task Load_collection_using_Query_not_found_untyped(EntityState state, bool async) @@ -918,7 +918,7 @@ public override async Task Load_collection_using_Query_not_found_untyped(EntityS SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal_using_Query_not_found_untyped(EntityState state, bool async) @@ -954,7 +954,7 @@ public override async Task Load_one_to_one_reference_to_dependent_using_Query_no SELECT [s].[Id], [s].[ParentId] FROM [Single] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override async Task Load_collection_already_loaded_untyped(EntityState state, bool async, CascadeTiming cascadeDeleteTiming) @@ -996,7 +996,7 @@ public override async Task Load_collection_using_Query_already_loaded_untyped( SELECT [c].[Id], [c].[ParentId] FROM [Child] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal_using_Query_already_loaded_untyped(EntityState state, bool async) @@ -1033,7 +1033,7 @@ public override async Task Load_one_to_one_reference_to_dependent_using_Query_al SELECT [s].[Id], [s].[ParentId] FROM [Single] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override async Task Load_collection_alternate_key(EntityState state, bool async) @@ -1045,7 +1045,7 @@ public override async Task Load_collection_alternate_key(EntityState state, bool SELECT [c].[Id], [c].[ParentId] FROM [ChildAk] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal_alternate_key(EntityState state, bool async) @@ -1081,7 +1081,7 @@ public override async Task Load_one_to_one_reference_to_dependent_alternate_key( SELECT [s].[Id], [s].[ParentId] FROM [SingleAk] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override async Task Load_collection_using_Query_alternate_key(EntityState state, bool async) @@ -1093,7 +1093,7 @@ public override async Task Load_collection_using_Query_alternate_key(EntityState SELECT [c].[Id], [c].[ParentId] FROM [ChildAk] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal_using_Query_alternate_key(EntityState state, bool async) @@ -1129,7 +1129,7 @@ public override async Task Load_one_to_one_reference_to_dependent_using_Query_al SELECT TOP(2) [s].[Id], [s].[ParentId] FROM [SingleAk] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal_null_FK_alternate_key(EntityState state, bool async) @@ -1175,7 +1175,7 @@ public override async Task Load_collection_shadow_fk(EntityState state, bool asy SELECT [c].[Id], [c].[ParentId] FROM [ChildShadowFk] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal_shadow_fk(EntityState state, bool async) @@ -1211,7 +1211,7 @@ public override async Task Load_one_to_one_reference_to_dependent_shadow_fk(Enti SELECT [s].[Id], [s].[ParentId] FROM [SingleShadowFk] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override async Task Load_collection_using_Query_shadow_fk(EntityState state, bool async) @@ -1223,7 +1223,7 @@ public override async Task Load_collection_using_Query_shadow_fk(EntityState sta SELECT [c].[Id], [c].[ParentId] FROM [ChildShadowFk] AS [c] -WHERE ([c].[ParentId] = @__p_0) AND [c].[ParentId] IS NOT NULL"); +WHERE [c].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal_using_Query_shadow_fk(EntityState state, bool async) @@ -1259,7 +1259,7 @@ public override async Task Load_one_to_one_reference_to_dependent_using_Query_sh SELECT TOP(2) [s].[Id], [s].[ParentId] FROM [SingleShadowFk] AS [s] -WHERE ([s].[ParentId] = @__p_0) AND [s].[ParentId] IS NOT NULL"); +WHERE [s].[ParentId] = @__p_0"); } public override async Task Load_many_to_one_reference_to_principal_null_FK_shadow_fk(EntityState state, bool async) @@ -1306,7 +1306,7 @@ public override async Task Load_collection_composite_key(EntityState state, bool SELECT [c].[Id], [c].[ParentAlternateId], [c].[ParentId] FROM [ChildCompositeKey] AS [c] -WHERE (([c].[ParentAlternateId] = @__p_0) AND [c].[ParentAlternateId] IS NOT NULL) AND (([c].[ParentId] = @__p_1) AND [c].[ParentId] IS NOT NULL)"); +WHERE ([c].[ParentAlternateId] = @__p_0) AND ([c].[ParentId] = @__p_1)"); } public override async Task Load_many_to_one_reference_to_principal_composite_key(EntityState state, bool async) @@ -1345,7 +1345,7 @@ public override async Task Load_one_to_one_reference_to_dependent_composite_key( SELECT [s].[Id], [s].[ParentAlternateId], [s].[ParentId] FROM [SingleCompositeKey] AS [s] -WHERE (([s].[ParentAlternateId] = @__p_0) AND [s].[ParentAlternateId] IS NOT NULL) AND (([s].[ParentId] = @__p_1) AND [s].[ParentId] IS NOT NULL)"); +WHERE ([s].[ParentAlternateId] = @__p_0) AND ([s].[ParentId] = @__p_1)"); } public override async Task Load_collection_using_Query_composite_key(EntityState state, bool async) @@ -1358,7 +1358,7 @@ public override async Task Load_collection_using_Query_composite_key(EntityState SELECT [c].[Id], [c].[ParentAlternateId], [c].[ParentId] FROM [ChildCompositeKey] AS [c] -WHERE (([c].[ParentAlternateId] = @__p_0) AND [c].[ParentAlternateId] IS NOT NULL) AND (([c].[ParentId] = @__p_1) AND [c].[ParentId] IS NOT NULL)"); +WHERE ([c].[ParentAlternateId] = @__p_0) AND ([c].[ParentId] = @__p_1)"); } public override async Task Load_many_to_one_reference_to_principal_using_Query_composite_key(EntityState state, bool async) @@ -1397,7 +1397,7 @@ public override async Task Load_one_to_one_reference_to_dependent_using_Query_co SELECT TOP(2) [s].[Id], [s].[ParentAlternateId], [s].[ParentId] FROM [SingleCompositeKey] AS [s] -WHERE (([s].[ParentAlternateId] = @__p_0) AND [s].[ParentAlternateId] IS NOT NULL) AND (([s].[ParentId] = @__p_1) AND [s].[ParentId] IS NOT NULL)"); +WHERE ([s].[ParentAlternateId] = @__p_0) AND ([s].[ParentId] = @__p_1)"); } public override async Task Load_many_to_one_reference_to_principal_null_FK_composite_key(EntityState state, bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs index 76c1497e498..bbd194fb41d 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs @@ -30,7 +30,7 @@ public override async Task Entity_equality_empty(bool isAsync) @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] -WHERE ([l0].[Id] = 0) AND [l0].[Id] IS NOT NULL"); +WHERE [l0].[Id] = 0"); } public override async Task Key_equality_when_sentinel_ef_property(bool isAsync) @@ -41,7 +41,7 @@ public override async Task Key_equality_when_sentinel_ef_property(bool isAsync) @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] -WHERE ([l0].[Id] = 0) AND [l0].[Id] IS NOT NULL"); +WHERE [l0].[Id] = 0"); } public override async Task Key_equality_using_property_method_required(bool isAsync) @@ -74,7 +74,7 @@ public override async Task Key_equality_using_property_method_nested(bool isAsyn @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Required_Id] -WHERE ([l0].[Id] = 7) AND [l0].[Id] IS NOT NULL"); +WHERE [l0].[Id] = 7"); } public override async Task Key_equality_using_property_method_nested2(bool isAsync) @@ -96,7 +96,7 @@ public override async Task Key_equality_using_property_method_and_member_express @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Required_Id] -WHERE ([l0].[Id] = 7) AND [l0].[Id] IS NOT NULL"); +WHERE [l0].[Id] = 7"); } public override async Task Key_equality_using_property_method_and_member_expression2(bool isAsync) @@ -107,7 +107,7 @@ public override async Task Key_equality_using_property_method_and_member_express @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Required_Id] -WHERE ([l0].[Id] = 7) AND [l0].[Id] IS NOT NULL"); +WHERE [l0].[Id] = 7"); } public override async Task Key_equality_using_property_method_and_member_expression3(bool isAsync) @@ -140,7 +140,7 @@ public override async Task Key_equality_two_conditions_on_same_navigation(bool i @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Required_Id] -WHERE (([l0].[Id] = 1) AND [l0].[Id] IS NOT NULL) OR (([l0].[Id] = 2) AND [l0].[Id] IS NOT NULL)"); +WHERE ([l0].[Id] = 1) OR ([l0].[Id] = 2)"); } public override async Task Key_equality_two_conditions_on_same_navigation2(bool isAsync) @@ -304,7 +304,7 @@ public override async Task Optional_navigation_inside_property_method_translated @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] -WHERE ([l0].[Name] = N'L2 01') AND [l0].[Name] IS NOT NULL"); +WHERE [l0].[Name] = N'L2 01'"); } public override async Task Optional_navigation_inside_nested_method_call_translated_to_join(bool isAsync) @@ -326,7 +326,7 @@ public override async Task Method_call_on_optional_navigation_translates_to_null @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] -WHERE (([l0].[Name] = N'') AND [l0].[Name] IS NOT NULL) OR ([l0].[Name] IS NOT NULL AND (LEFT([l0].[Name], LEN([l0].[Name])) = [l0].[Name]))"); +WHERE ([l0].[Name] = N'') OR ([l0].[Name] IS NOT NULL AND ([l0].[Name] IS NOT NULL AND (LEFT([l0].[Name], LEN([l0].[Name])) = [l0].[Name])))"); } public override async Task Optional_navigation_inside_method_call_translated_to_join_keeps_original_nullability(bool isAsync) @@ -645,7 +645,7 @@ public override async Task Where_nav_prop_reference_optional1(bool isAsync) @"SELECT [l].[Id] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] -WHERE (([l0].[Name] = N'L2 05') AND [l0].[Name] IS NOT NULL) OR (([l0].[Name] = N'L2 07') AND [l0].[Name] IS NOT NULL)"); +WHERE ([l0].[Name] = N'L2 05') OR ([l0].[Name] = N'L2 07')"); } public override async Task Where_nav_prop_reference_optional1_via_DefaultIfEmpty(bool isAsync) @@ -657,7 +657,7 @@ public override async Task Where_nav_prop_reference_optional1_via_DefaultIfEmpty FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] LEFT JOIN [LevelTwo] AS [l1] ON [l].[Id] = [l1].[Level1_Optional_Id] -WHERE (([l0].[Name] = N'L2 05') AND [l0].[Name] IS NOT NULL) OR (([l1].[Name] = N'L2 07') AND [l1].[Name] IS NOT NULL)"); +WHERE ([l0].[Name] = N'L2 05') OR ([l1].[Name] = N'L2 07')"); } public override async Task Where_nav_prop_reference_optional2(bool isAsync) @@ -668,7 +668,7 @@ public override async Task Where_nav_prop_reference_optional2(bool isAsync) @"SELECT [l].[Id] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] -WHERE (([l0].[Name] = N'L2 05') AND [l0].[Name] IS NOT NULL) OR (([l0].[Name] <> N'L2 42') OR [l0].[Name] IS NULL)"); +WHERE ([l0].[Name] = N'L2 05') OR (([l0].[Name] <> N'L2 42') OR [l0].[Name] IS NULL)"); } public override async Task Where_nav_prop_reference_optional2_via_DefaultIfEmpty(bool isAsync) @@ -680,7 +680,7 @@ public override async Task Where_nav_prop_reference_optional2_via_DefaultIfEmpty FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] LEFT JOIN [LevelTwo] AS [l1] ON [l].[Id] = [l1].[Level1_Optional_Id] -WHERE (([l0].[Name] = N'L2 05') AND [l0].[Name] IS NOT NULL) OR (([l1].[Name] <> N'L2 42') OR [l1].[Name] IS NULL)"); +WHERE ([l0].[Name] = N'L2 05') OR (([l1].[Name] <> N'L2 42') OR [l1].[Name] IS NULL)"); } public override async Task Select_multiple_nav_prop_reference_optional(bool isAsync) @@ -844,7 +844,7 @@ public override async Task SelectMany_navigation_comparison2(bool isAsync) FROM [LevelOne] AS [l] CROSS JOIN [LevelTwo] AS [l0] LEFT JOIN [LevelOne] AS [l1] ON [l0].[Level1_Optional_Id] = [l1].[Id] -WHERE ([l].[Id] = [l1].[Id]) AND [l1].[Id] IS NOT NULL"); +WHERE [l].[Id] = [l1].[Id]"); } public override async Task SelectMany_navigation_comparison3(bool isAsync) @@ -856,7 +856,7 @@ public override async Task SelectMany_navigation_comparison3(bool isAsync) FROM [LevelOne] AS [l] CROSS JOIN [LevelTwo] AS [l0] LEFT JOIN [LevelTwo] AS [l1] ON [l].[Id] = [l1].[Level1_Optional_Id] -WHERE ([l1].[Id] = [l0].[Id]) AND [l1].[Id] IS NOT NULL"); +WHERE [l1].[Id] = [l0].[Id]"); } public override async Task Where_complex_predicate_with_with_nav_prop_and_OrElse1(bool isAsync) @@ -869,7 +869,7 @@ FROM [LevelOne] AS [l] CROSS JOIN [LevelTwo] AS [l0] LEFT JOIN [LevelTwo] AS [l1] ON [l].[Id] = [l1].[Level1_Optional_Id] INNER JOIN [LevelOne] AS [l2] ON [l0].[Level1_Required_Id] = [l2].[Id] -WHERE (([l1].[Name] = N'L2 01') AND [l1].[Name] IS NOT NULL) OR (([l2].[Name] <> N'Bar') OR [l2].[Name] IS NULL)"); +WHERE ([l1].[Name] = N'L2 01') OR (([l2].[Name] <> N'Bar') OR [l2].[Name] IS NULL)"); } public override async Task Where_complex_predicate_with_with_nav_prop_and_OrElse2(bool isAsync) @@ -881,7 +881,7 @@ public override async Task Where_complex_predicate_with_with_nav_prop_and_OrElse FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] LEFT JOIN [LevelThree] AS [l1] ON [l0].[Id] = [l1].[Level2_Required_Id] -WHERE (([l1].[Name] = N'L3 05') AND [l1].[Name] IS NOT NULL) OR (([l0].[Name] <> N'L2 05') OR [l0].[Name] IS NULL)"); +WHERE ([l1].[Name] = N'L3 05') OR (([l0].[Name] <> N'L2 05') OR [l0].[Name] IS NULL)"); } public override async Task Where_complex_predicate_with_with_nav_prop_and_OrElse3(bool isAsync) @@ -894,7 +894,7 @@ FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] LEFT JOIN [LevelTwo] AS [l1] ON [l].[Id] = [l1].[Level1_Required_Id] LEFT JOIN [LevelThree] AS [l2] ON [l1].[Id] = [l2].[Level2_Optional_Id] -WHERE (([l0].[Name] <> N'L2 05') OR [l0].[Name] IS NULL) OR (([l2].[Name] = N'L3 05') AND [l2].[Name] IS NOT NULL)"); +WHERE (([l0].[Name] <> N'L2 05') OR [l0].[Name] IS NULL) OR ([l2].[Name] = N'L3 05')"); } public override async Task Where_complex_predicate_with_with_nav_prop_and_OrElse4(bool isAsync) @@ -907,7 +907,7 @@ FROM [LevelThree] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Level2_Optional_Id] = [l0].[Id] INNER JOIN [LevelTwo] AS [l1] ON [l].[Level2_Required_Id] = [l1].[Id] LEFT JOIN [LevelOne] AS [l2] ON [l1].[Level1_Optional_Id] = [l2].[Id] -WHERE (([l0].[Name] <> N'L2 05') OR [l0].[Name] IS NULL) OR (([l2].[Name] = N'L1 05') AND [l2].[Name] IS NOT NULL)"); +WHERE (([l0].[Name] <> N'L2 05') OR [l0].[Name] IS NULL) OR ([l2].[Name] = N'L1 05')"); } public override async Task Complex_navigations_with_predicate_projected_into_anonymous_type(bool isAsync) @@ -920,7 +920,7 @@ FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Required_Id] LEFT JOIN [LevelThree] AS [l1] ON [l0].[Id] = [l1].[Level2_Required_Id] LEFT JOIN [LevelThree] AS [l2] ON [l0].[Id] = [l2].[Level2_Optional_Id] -WHERE ((([l1].[Id] = [l2].[Id]) AND ([l1].[Id] IS NOT NULL AND [l2].[Id] IS NOT NULL)) OR ([l1].[Id] IS NULL AND [l2].[Id] IS NULL)) AND (([l2].[Id] <> 7) OR [l2].[Id] IS NULL)"); +WHERE (([l1].[Id] = [l2].[Id]) OR ([l1].[Id] IS NULL AND [l2].[Id] IS NULL)) AND (([l2].[Id] <> 7) OR [l2].[Id] IS NULL)"); } public override async Task Complex_navigations_with_predicate_projected_into_anonymous_type2(bool isAsync) @@ -933,7 +933,7 @@ FROM [LevelThree] AS [l] INNER JOIN [LevelTwo] AS [l0] ON [l].[Level2_Required_Id] = [l0].[Id] INNER JOIN [LevelOne] AS [l1] ON [l0].[Level1_Required_Id] = [l1].[Id] LEFT JOIN [LevelOne] AS [l2] ON [l0].[Level1_Optional_Id] = [l2].[Id] -WHERE (([l1].[Id] = [l2].[Id]) AND [l2].[Id] IS NOT NULL) AND (([l2].[Id] <> 7) OR [l2].[Id] IS NULL)"); +WHERE ([l1].[Id] = [l2].[Id]) AND (([l2].[Id] <> 7) OR [l2].[Id] IS NULL)"); } public override async Task Optional_navigation_projected_into_DTO(bool isAsync) @@ -1269,7 +1269,7 @@ FROM [LevelThree] AS [l] WHERE ( SELECT COUNT(*) FROM [LevelThree] AS [l1] - WHERE ([l0].[Id] = [l1].[OneToMany_Optional_Inverse3Id]) AND [l1].[OneToMany_Optional_Inverse3Id] IS NOT NULL) > 0"); + WHERE [l0].[Id] = [l1].[OneToMany_Optional_Inverse3Id]) > 0"); } public override async Task Where_navigation_property_to_collection_of_original_entity_type(bool isAsync) @@ -1283,7 +1283,7 @@ FROM [LevelTwo] AS [l] WHERE ( SELECT COUNT(*) FROM [LevelTwo] AS [l1] - WHERE ([l0].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND [l1].[OneToMany_Optional_Inverse2Id] IS NOT NULL) > 0"); + WHERE [l0].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) > 0"); } public override async Task Complex_multi_include_with_order_by_and_paging(bool isAsync) @@ -1630,7 +1630,7 @@ public override async Task Projection_select_correct_table_from_subquery_when_ma SELECT TOP(@__p_0) [l].[Name] FROM [LevelTwo] AS [l] INNER JOIN [LevelOne] AS [l0] ON [l].[Level1_Required_Id] = [l0].[Id] -WHERE ([l0].[Name] = N'L1 03') AND [l0].[Name] IS NOT NULL +WHERE [l0].[Name] = N'L1 03' ORDER BY [l].[Id]"); } @@ -1645,7 +1645,7 @@ SELECT TOP(@__p_0) [l].[Name] FROM [LevelTwo] AS [l] INNER JOIN [LevelOne] AS [l0] ON [l].[Level1_Required_Id] = [l0].[Id] INNER JOIN [LevelThree] AS [l1] ON [l0].[Id] = [l1].[Level2_Required_Id] -WHERE (([l0].[Name] = N'L1 03') AND [l0].[Name] IS NOT NULL) AND (([l1].[Name] = N'L3 08') AND [l1].[Name] IS NOT NULL) +WHERE ([l0].[Name] = N'L1 03') AND ([l1].[Name] = N'L3 08') ORDER BY [l0].[Id]"); } @@ -1661,7 +1661,7 @@ SELECT TOP(@__p_0) [l0].[Name] FROM [LevelTwo] AS [l] INNER JOIN [LevelOne] AS [l0] ON [l].[Level1_Required_Id] = [l0].[Id] INNER JOIN [LevelThree] AS [l1] ON [l0].[Id] = [l1].[Level2_Required_Id] -WHERE (([l0].[Name] = N'L1 03') AND [l0].[Name] IS NOT NULL) AND (([l1].[Name] = N'L3 08') AND [l1].[Name] IS NOT NULL) +WHERE ([l0].[Name] = N'L1 03') AND ([l1].[Name] = N'L3 08') ORDER BY [l0].[Id]"); } @@ -1675,7 +1675,7 @@ public override async Task Where_predicate_on_optional_reference_navigation(bool SELECT TOP(@__p_0) [l].[Name] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Required_Id] -WHERE ([l0].[Name] = N'L2 03') AND [l0].[Name] IS NOT NULL +WHERE [l0].[Name] = N'L2 03' ORDER BY [l].[Id]"); } @@ -2002,7 +2002,6 @@ INNER JOIN ( FROM [LevelTwo] AS [l0] ) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] LEFT JOIN [LevelTwo] AS [l1] ON [l].[Id] = [l1].[OneToMany_Optional_Inverse2Id] -WHERE CAST(1 AS bit) = CAST(1 AS bit) ORDER BY [l].[Id], [t].[Id], [l1].[Id]"); } @@ -2346,15 +2345,11 @@ public override async Task Required_navigation_on_a_subquery_with_First_in_predi AssertSql( @"SELECT [l].[Id], [l].[Date], [l].[Level1_Optional_Id], [l].[Level1_Required_Id], [l].[Name], [l].[OneToMany_Optional_Inverse2Id], [l].[OneToMany_Optional_Self_Inverse2Id], [l].[OneToMany_Required_Inverse2Id], [l].[OneToMany_Required_Self_Inverse2Id], [l].[OneToOne_Optional_PK_Inverse2Id], [l].[OneToOne_Optional_Self2Id] FROM [LevelTwo] AS [l] -WHERE ([l].[Id] = 7) AND ((( +WHERE ([l].[Id] = 7) AND (( SELECT TOP(1) [l1].[Name] FROM [LevelTwo] AS [l0] INNER JOIN [LevelOne] AS [l1] ON [l0].[Level1_Required_Id] = [l1].[Id] - ORDER BY [l0].[Id]) = N'L1 02') AND ( - SELECT TOP(1) [l1].[Name] - FROM [LevelTwo] AS [l0] - INNER JOIN [LevelOne] AS [l1] ON [l0].[Level1_Required_Id] = [l1].[Id] - ORDER BY [l0].[Id]) IS NOT NULL)"); + ORDER BY [l0].[Id]) = N'L1 02')"); } public override async Task Manually_created_left_join_propagates_nullability_to_navigations(bool isAsync) @@ -2868,7 +2863,7 @@ SELECT [l].[Name] FROM [LevelThree] AS [l] INNER JOIN [LevelTwo] AS [l0] ON [l].[OneToMany_Required_Inverse3Id] = [l0].[Id] INNER JOIN [LevelOne] AS [l1] ON [l0].[Level1_Required_Id] = [l1].[Id] -WHERE ([l1].[Name] = N'L1 03') AND [l1].[Name] IS NOT NULL +WHERE [l1].[Name] = N'L1 03' ORDER BY [l].[Level2_Required_Id] OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY"); } @@ -2890,7 +2885,7 @@ public override async Task Join_condition_optimizations_applied_correctly_when_a AssertSql( @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id] FROM [LevelOne] AS [l] -INNER JOIN [LevelTwo] AS [l0] ON ((([l].[OneToMany_Optional_Self_Inverse1Id] = [l0].[Level1_Optional_Id]) AND ([l].[OneToMany_Optional_Self_Inverse1Id] IS NOT NULL AND [l0].[Level1_Optional_Id] IS NOT NULL)) OR ([l].[OneToMany_Optional_Self_Inverse1Id] IS NULL AND [l0].[Level1_Optional_Id] IS NULL)) AND ((([l].[OneToOne_Optional_Self1Id] = [l0].[OneToMany_Optional_Self_Inverse2Id]) AND ([l].[OneToOne_Optional_Self1Id] IS NOT NULL AND [l0].[OneToMany_Optional_Self_Inverse2Id] IS NOT NULL)) OR ([l].[OneToOne_Optional_Self1Id] IS NULL AND [l0].[OneToMany_Optional_Self_Inverse2Id] IS NULL))"); +INNER JOIN [LevelTwo] AS [l0] ON (([l].[OneToMany_Optional_Self_Inverse1Id] = [l0].[Level1_Optional_Id]) OR ([l].[OneToMany_Optional_Self_Inverse1Id] IS NULL AND [l0].[Level1_Optional_Id] IS NULL)) AND (([l].[OneToOne_Optional_Self1Id] = [l0].[OneToMany_Optional_Self_Inverse2Id]) OR ([l].[OneToOne_Optional_Self1Id] IS NULL AND [l0].[OneToMany_Optional_Self_Inverse2Id] IS NULL))"); } public override async Task Navigation_filter_navigation_grouping_ordering_by_group_key(bool isAsync) @@ -2967,8 +2962,7 @@ public override async Task Navigations_compared_to_each_other1(bool isAsync) AssertSql( @"SELECT [l].[Name] FROM [LevelTwo] AS [l] -INNER JOIN [LevelOne] AS [l0] ON [l].[OneToMany_Required_Inverse2Id] = [l0].[Id] -WHERE [l0].[Id] = [l0].[Id]"); +INNER JOIN [LevelOne] AS [l0] ON [l].[OneToMany_Required_Inverse2Id] = [l0].[Id]"); } public override async Task Navigations_compared_to_each_other2(bool isAsync) @@ -2980,7 +2974,7 @@ public override async Task Navigations_compared_to_each_other2(bool isAsync) FROM [LevelTwo] AS [l] INNER JOIN [LevelOne] AS [l0] ON [l].[OneToMany_Required_Inverse2Id] = [l0].[Id] LEFT JOIN [LevelOne] AS [l1] ON [l].[OneToOne_Optional_PK_Inverse2Id] = [l1].[Id] -WHERE ([l0].[Id] = [l1].[Id]) AND [l1].[Id] IS NOT NULL"); +WHERE [l0].[Id] = [l1].[Id]"); } public override async Task Navigations_compared_to_each_other3(bool isAsync) @@ -2993,7 +2987,7 @@ FROM [LevelTwo] AS [l] WHERE EXISTS ( SELECT 1 FROM [LevelThree] AS [l0] - WHERE ([l].[Id] = [l0].[OneToMany_Optional_Inverse3Id]) AND [l0].[OneToMany_Optional_Inverse3Id] IS NOT NULL)"); + WHERE [l].[Id] = [l0].[OneToMany_Optional_Inverse3Id])"); } public override async Task Navigations_compared_to_each_other4(bool isAsync) @@ -4185,7 +4179,7 @@ FROM [LevelTwo] AS [l0] SELECT COUNT(*) FROM [LevelTwo] AS [l3] LEFT JOIN [LevelThree] AS [l4] ON [l3].[Id] = [l4].[OneToOne_Optional_PK_Inverse3Id] - WHERE (([l].[Id] = [l3].[OneToMany_Optional_Inverse2Id]) AND [l3].[OneToMany_Optional_Inverse2Id] IS NOT NULL) AND (([l4].[Name] <> N'Foo') OR [l4].[Name] IS NULL)) > 0 + WHERE ([l].[Id] = [l3].[OneToMany_Optional_Inverse2Id]) AND (([l4].[Name] <> N'Foo') OR [l4].[Name] IS NULL)) > 0 ORDER BY [l].[Id], [t].[Id]"); } @@ -4253,7 +4247,7 @@ FROM [LevelThree] AS [l1] WHERE [l1].[Level2_Required_Id] = [l2].[Id] ORDER BY [l1].[Id]) FROM [LevelTwo] AS [l2] - WHERE ([l2].[Level1_Optional_Id] = [l].[Id]) AND [l2].[Level1_Optional_Id] IS NOT NULL + WHERE [l2].[Level1_Optional_Id] = [l].[Id] ORDER BY [l2].[Id]) <> N'Foo') OR ( SELECT TOP(1) ( SELECT TOP(1) ( @@ -4265,7 +4259,7 @@ FROM [LevelThree] AS [l1] WHERE [l1].[Level2_Required_Id] = [l2].[Id] ORDER BY [l1].[Id]) FROM [LevelTwo] AS [l2] - WHERE ([l2].[Level1_Optional_Id] = [l].[Id]) AND [l2].[Level1_Optional_Id] IS NOT NULL + WHERE [l2].[Level1_Optional_Id] = [l].[Id] ORDER BY [l2].[Id]) IS NULL ORDER BY [l].[Id]"); } @@ -4317,7 +4311,7 @@ FROM [LevelFour] AS [l] WHERE [l].[Level3_Required_Id] = [l0].[Id] ORDER BY [l].[Id]) FROM [LevelThree] AS [l0] - WHERE ([l1].[Id] = [l0].[OneToMany_Optional_Inverse3Id]) AND [l0].[OneToMany_Optional_Inverse3Id] IS NOT NULL) + WHERE [l1].[Id] = [l0].[OneToMany_Optional_Inverse3Id]) FROM [LevelTwo] AS [l1] WHERE [l1].[Level1_Required_Id] = [l2].[Id] ORDER BY [l1].[Id]) @@ -4336,19 +4330,15 @@ FROM [LevelThree] AS [l] WHERE ( SELECT TOP(1) [l0].[Id] FROM [LevelTwo] AS [l0] - WHERE ([l2].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) AND [l0].[OneToMany_Optional_Inverse2Id] IS NOT NULL - ORDER BY [l0].[Id]) IS NOT NULL AND (((( - SELECT TOP(1) [l1].[Id] - FROM [LevelTwo] AS [l1] - WHERE ([l2].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND [l1].[OneToMany_Optional_Inverse2Id] IS NOT NULL - ORDER BY [l1].[Id]) = [l].[OneToMany_Optional_Inverse3Id]) AND (( + WHERE [l2].[Id] = [l0].[OneToMany_Optional_Inverse2Id] + ORDER BY [l0].[Id]) IS NOT NULL AND ((( SELECT TOP(1) [l1].[Id] FROM [LevelTwo] AS [l1] - WHERE ([l2].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND [l1].[OneToMany_Optional_Inverse2Id] IS NOT NULL - ORDER BY [l1].[Id]) IS NOT NULL AND [l].[OneToMany_Optional_Inverse3Id] IS NOT NULL)) OR (( + WHERE [l2].[Id] = [l1].[OneToMany_Optional_Inverse2Id] + ORDER BY [l1].[Id]) = [l].[OneToMany_Optional_Inverse3Id]) OR (( SELECT TOP(1) [l1].[Id] FROM [LevelTwo] AS [l1] - WHERE ([l2].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND [l1].[OneToMany_Optional_Inverse2Id] IS NOT NULL + WHERE [l2].[Id] = [l1].[OneToMany_Optional_Inverse2Id] ORDER BY [l1].[Id]) IS NULL AND [l].[OneToMany_Optional_Inverse3Id] IS NULL)) ORDER BY [l].[Id]) FROM [LevelOne] AS [l2]"); @@ -4371,19 +4361,13 @@ FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] LEFT JOIN [LevelThree] AS [l1] ON [l0].[Id] = [l1].[Level2_Optional_Id] LEFT JOIN [LevelFour] AS [l2] ON [l1].[Id] = [l2].[Level3_Optional_Id] -WHERE (CASE - WHEN [l0].[Id] IS NULL THEN NULL - ELSE CASE - WHEN [l1].[Id] IS NULL THEN NULL - ELSE [l2].[Name] - END -END = N'L4 01') AND CASE +WHERE CASE WHEN [l0].[Id] IS NULL THEN NULL ELSE CASE WHEN [l1].[Id] IS NULL THEN NULL ELSE [l2].[Name] END -END IS NOT NULL"); +END = N'L4 01'"); } public override async Task Union_over_entities_with_different_nullability(bool isAsync) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/DbFunctionsSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/DbFunctionsSqlServerTest.cs index c54bff94e52..817074f5985 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/DbFunctionsSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/DbFunctionsSqlServerTest.cs @@ -428,7 +428,7 @@ public virtual void DateDiff_Year() AssertSql( @"SELECT COUNT(*) FROM [Orders] AS [o] -WHERE (DATEDIFF(YEAR, [o].[OrderDate], GETDATE()) = 0) AND DATEDIFF(YEAR, [o].[OrderDate], GETDATE()) IS NOT NULL"); +WHERE DATEDIFF(YEAR, [o].[OrderDate], GETDATE()) = 0"); } } @@ -444,7 +444,7 @@ public virtual void DateDiff_Month() AssertSql( @"SELECT COUNT(*) FROM [Orders] AS [o] -WHERE (DATEDIFF(MONTH, [o].[OrderDate], GETDATE()) = 0) AND DATEDIFF(MONTH, [o].[OrderDate], GETDATE()) IS NOT NULL"); +WHERE DATEDIFF(MONTH, [o].[OrderDate], GETDATE()) = 0"); } } @@ -460,7 +460,7 @@ public virtual void DateDiff_Day() AssertSql( @"SELECT COUNT(*) FROM [Orders] AS [o] -WHERE (DATEDIFF(DAY, [o].[OrderDate], GETDATE()) = 0) AND DATEDIFF(DAY, [o].[OrderDate], GETDATE()) IS NOT NULL"); +WHERE DATEDIFF(DAY, [o].[OrderDate], GETDATE()) = 0"); } } @@ -476,7 +476,7 @@ public virtual void DateDiff_Hour() AssertSql( @"SELECT COUNT(*) FROM [Orders] AS [o] -WHERE (DATEDIFF(HOUR, [o].[OrderDate], GETDATE()) = 0) AND DATEDIFF(HOUR, [o].[OrderDate], GETDATE()) IS NOT NULL"); +WHERE DATEDIFF(HOUR, [o].[OrderDate], GETDATE()) = 0"); } } @@ -492,7 +492,7 @@ public virtual void DateDiff_Minute() AssertSql( @"SELECT COUNT(*) FROM [Orders] AS [o] -WHERE (DATEDIFF(MINUTE, [o].[OrderDate], GETDATE()) = 0) AND DATEDIFF(MINUTE, [o].[OrderDate], GETDATE()) IS NOT NULL"); +WHERE DATEDIFF(MINUTE, [o].[OrderDate], GETDATE()) = 0"); } } @@ -508,7 +508,7 @@ public virtual void DateDiff_Second() AssertSql( @"SELECT COUNT(*) FROM [Orders] AS [o] -WHERE (DATEDIFF(SECOND, [o].[OrderDate], GETDATE()) = 0) AND DATEDIFF(SECOND, [o].[OrderDate], GETDATE()) IS NOT NULL"); +WHERE DATEDIFF(SECOND, [o].[OrderDate], GETDATE()) = 0"); } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/FiltersSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/FiltersSqlServerTest.cs index f3ba0a9e8e2..6c4b6a6b75d 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/FiltersSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/FiltersSqlServerTest.cs @@ -26,7 +26,7 @@ public override void Count_query() SELECT COUNT(*) FROM [Customers] AS [c] -WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL))"); +WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0))"); } public override void Materialized_query() @@ -38,7 +38,7 @@ public override void Materialized_query() SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL))"); +WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0))"); } public override void Find() @@ -51,7 +51,7 @@ public override void Find() SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ((@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL))) AND ([c].[CustomerID] = @__p_0)"); +WHERE ((@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0))) AND ([c].[CustomerID] = @__p_0)"); } public override void Materialized_query_parameter() @@ -63,7 +63,7 @@ public override void Materialized_query_parameter() SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL))"); +WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0))"); } public override void Materialized_query_parameter_new_context() @@ -75,13 +75,13 @@ public override void Materialized_query_parameter_new_context() SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL))", +WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0))", // @"@__ef_filter__TenantPrefix_0='T' (Size = 4000) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL))"); +WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0))"); } public override void Projection_query_parameter() @@ -93,7 +93,7 @@ public override void Projection_query_parameter() SELECT [c].[CustomerID] FROM [Customers] AS [c] -WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL))"); +WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0))"); } public override void Projection_query() @@ -105,7 +105,7 @@ public override void Projection_query() SELECT [c].[CustomerID] FROM [Customers] AS [c] -WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL))"); +WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0))"); } public override void Include_query() @@ -123,11 +123,11 @@ FROM [Orders] AS [o] LEFT JOIN ( SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] - WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c0].[CompanyName] IS NOT NULL AND ((LEFT([c0].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c0].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL)) + WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c0].[CompanyName] IS NOT NULL AND (LEFT([c0].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0)) ) AS [t] ON [o].[CustomerID] = [t].[CustomerID] WHERE [t].[CustomerID] IS NOT NULL AND [t].[CompanyName] IS NOT NULL ) AS [t0] ON [c].[CustomerID] = [t0].[CustomerID] -WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL)) +WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0)) ORDER BY [c].[CustomerID], [t0].[OrderID]"); } @@ -154,7 +154,7 @@ FROM [Orders] AS [o] LEFT JOIN ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] - WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL)) + WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0)) ) AS [t] ON [o].[CustomerID] = [t].[CustomerID] WHERE [t].[CustomerID] IS NOT NULL AND [t].[CompanyName] IS NOT NULL"); } @@ -175,7 +175,7 @@ FROM [Orders] AS [o0] LEFT JOIN ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] - WHERE (@__ef_filter__TenantPrefix_1 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_1)) = @__ef_filter__TenantPrefix_1) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_1)) IS NOT NULL)) + WHERE (@__ef_filter__TenantPrefix_1 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_1)) = @__ef_filter__TenantPrefix_1)) ) AS [t] ON [o0].[CustomerID] = [t].[CustomerID] WHERE [t].[CustomerID] IS NOT NULL AND [t].[CompanyName] IS NOT NULL ) AS [t0] ON [o].[OrderID] = [t0].[OrderID] @@ -198,7 +198,7 @@ FROM [Orders] AS [o] LEFT JOIN ( SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] - WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c0].[CompanyName] IS NOT NULL AND ((LEFT([c0].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c0].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL)) + WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c0].[CompanyName] IS NOT NULL AND (LEFT([c0].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0)) ) AS [t] ON [o].[CustomerID] = [t].[CustomerID] WHERE [t].[CustomerID] IS NOT NULL AND [t].[CompanyName] IS NOT NULL ) AS [t0] ON [c].[CustomerID] = [t0].[CustomerID] @@ -207,7 +207,7 @@ INNER JOIN ( FROM [Order Details] AS [o0] WHERE [o0].[Quantity] > @__ef_filter___quantity_1 ) AS [t1] ON [t0].[OrderID] = [t1].[OrderID] -WHERE ((@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL))) AND ([t1].[Discount] < CAST(10 AS real))"); +WHERE ((@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0))) AND ([t1].[Discount] < CAST(10 AS real))"); } [ConditionalFact] @@ -227,7 +227,7 @@ public void FromSql_is_composed() FROM ( select * from Customers ) AS [c] -WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL))"); +WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0))"); } [ConditionalFact] @@ -250,7 +250,7 @@ public void FromSql_is_composed_when_filter_has_navigation() LEFT JOIN ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] - WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL)) + WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0)) ) AS [t] ON [o].[CustomerID] = [t].[CustomerID] WHERE [t].[CustomerID] IS NOT NULL AND [t].[CompanyName] IS NOT NULL"); } @@ -265,14 +265,14 @@ public override void Compiled_query() SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ((@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL))) AND ([c].[CustomerID] = @__customerID)", +WHERE ((@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0))) AND ([c].[CustomerID] = @__customerID)", // @"@__ef_filter__TenantPrefix_0='B' (Size = 4000) @__customerID='BLAUS' (Size = 5) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ((@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL))) AND ([c].[CustomerID] = @__customerID)"); +WHERE ((@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0))) AND ([c].[CustomerID] = @__customerID)"); } public override void Entity_Equality() @@ -287,7 +287,7 @@ FROM [Orders] AS [o] LEFT JOIN ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] - WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) IS NOT NULL)) + WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0)) ) AS [t] ON [o].[CustomerID] = [t].[CustomerID] WHERE [t].[CustomerID] IS NOT NULL AND [t].[CompanyName] IS NOT NULL"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs index 8379f3c1209..c471534a641 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs @@ -165,7 +165,7 @@ public override void FromSqlRaw_queryable_multiple_composed() CROSS JOIN ( SELECT * FROM ""Orders"" ) AS [o] -WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL"); +WHERE [c].[CustomerID] = [o].[CustomerID]"); } public override void FromSqlRaw_queryable_multiple_composed_with_closure_parameters() @@ -183,7 +183,7 @@ public override void FromSqlRaw_queryable_multiple_composed_with_closure_paramet CROSS JOIN ( SELECT * FROM ""Orders"" WHERE ""OrderDate"" BETWEEN @p0 AND @p1 ) AS [o] -WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL"); +WHERE [c].[CustomerID] = [o].[CustomerID]"); } public override void FromSqlRaw_queryable_multiple_composed_with_parameters_and_closure_parameters() @@ -202,7 +202,7 @@ public override void FromSqlRaw_queryable_multiple_composed_with_parameters_and_ CROSS JOIN ( SELECT * FROM ""Orders"" WHERE ""OrderDate"" BETWEEN @p1 AND @p2 ) AS [o] -WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL", +WHERE [c].[CustomerID] = [o].[CustomerID]", // @"p0='Berlin' (Size = 4000) p1='1998-04-01T00:00:00' @@ -215,7 +215,7 @@ CROSS JOIN ( CROSS JOIN ( SELECT * FROM ""Orders"" WHERE ""OrderDate"" BETWEEN @p1 AND @p2 ) AS [o] -WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL"); +WHERE [c].[CustomerID] = [o].[CustomerID]"); } public override void FromSqlRaw_queryable_multiple_line_query() @@ -238,7 +238,7 @@ public override void FromSqlRaw_queryable_composed_multiple_line_query() SELECT * FROM ""Customers"" ) AS [c] -WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = N'London'"); } public override void FromSqlRaw_queryable_with_parameters() @@ -301,7 +301,7 @@ public override void FromSqlInterpolated_queryable_multiple_composed_with_parame CROSS JOIN ( SELECT * FROM ""Orders"" WHERE ""OrderDate"" BETWEEN @p1 AND @p2 ) AS [o] -WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL", +WHERE [c].[CustomerID] = [o].[CustomerID]", // @"p0='Berlin' (Size = 4000) p1='1998-04-01T00:00:00' @@ -314,7 +314,7 @@ CROSS JOIN ( CROSS JOIN ( SELECT * FROM ""Orders"" WHERE ""OrderDate"" BETWEEN @p1 AND @p2 ) AS [o] -WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL"); +WHERE [c].[CustomerID] = [o].[CustomerID]"); } public override void FromSqlRaw_queryable_with_null_parameter() @@ -339,7 +339,7 @@ public override void FromSqlRaw_queryable_with_parameters_and_closure() FROM ( SELECT * FROM ""Customers"" WHERE ""City"" = @p0 ) AS [c] -WHERE ([c].[ContactTitle] = @__contactTitle_1) AND [c].[ContactTitle] IS NOT NULL"); +WHERE [c].[ContactTitle] = @__contactTitle_1"); } public override void FromSqlRaw_queryable_simple_cache_key_includes_query_string() @@ -414,7 +414,7 @@ public override void FromSqlRaw_queryable_simple_composed_include() SELECT * FROM ""Customers"" ) AS [c] LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] -WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL +WHERE [c].[City] = N'London' ORDER BY [c].[CustomerID], [o].[OrderID]"); } @@ -438,7 +438,7 @@ public override void FromSqlRaw_composed_with_nullable_predicate() FROM ( SELECT * FROM ""Customers"" ) AS [c] -WHERE (([c].[ContactName] = [c].[CompanyName]) AND ([c].[ContactName] IS NOT NULL AND [c].[CompanyName] IS NOT NULL)) OR ([c].[ContactName] IS NULL AND [c].[CompanyName] IS NULL)"); +WHERE ([c].[ContactName] = [c].[CompanyName]) OR ([c].[ContactName] IS NULL AND [c].[CompanyName] IS NULL)"); ; } @@ -756,7 +756,7 @@ public override void Entity_equality_through_fromsql() SELECT * FROM ""Orders"" ) AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] -WHERE ([c].[CustomerID] = N'VINET') AND [c].[CustomerID] IS NOT NULL"); +WHERE [c].[CustomerID] = N'VINET'"); } public override void FromSqlRaw_with_set_operation() diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/FunkyDataQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/FunkyDataQuerySqlServerTest.cs index 918bdfb3669..a36e403f854 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/FunkyDataQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/FunkyDataQuerySqlServerTest.cs @@ -115,7 +115,7 @@ public override async Task String_contains_on_argument_with_wildcard_column(bool @"SELECT [f].[FirstName] AS [fn], [f0].[LastName] AS [ln] FROM [FunkyCustomers] AS [f] CROSS JOIN [FunkyCustomers] AS [f0] -WHERE (([f0].[LastName] = N'') AND [f0].[LastName] IS NOT NULL) OR (CHARINDEX([f0].[LastName], [f].[FirstName]) > 0)"); +WHERE ([f0].[LastName] = N'') OR (CHARINDEX([f0].[LastName], [f].[FirstName]) > 0)"); } public override async Task String_contains_on_argument_with_wildcard_column_negated(bool isAsync) @@ -175,13 +175,13 @@ public override async Task String_starts_with_on_argument_with_wildcard_paramete SELECT [f].[FirstName] FROM [FunkyCustomers] AS [f] -WHERE (@__prm1_0 = N'') OR ([f].[FirstName] IS NOT NULL AND ((LEFT([f].[FirstName], LEN(@__prm1_0)) = @__prm1_0) AND LEFT([f].[FirstName], LEN(@__prm1_0)) IS NOT NULL))", +WHERE (@__prm1_0 = N'') OR ([f].[FirstName] IS NOT NULL AND (LEFT([f].[FirstName], LEN(@__prm1_0)) = @__prm1_0))", // @"@__prm2_0='a_' (Size = 4000) SELECT [f].[FirstName] FROM [FunkyCustomers] AS [f] -WHERE (@__prm2_0 = N'') OR ([f].[FirstName] IS NOT NULL AND ((LEFT([f].[FirstName], LEN(@__prm2_0)) = @__prm2_0) AND LEFT([f].[FirstName], LEN(@__prm2_0)) IS NOT NULL))", +WHERE (@__prm2_0 = N'') OR ([f].[FirstName] IS NOT NULL AND (LEFT([f].[FirstName], LEN(@__prm2_0)) = @__prm2_0))", // @"SELECT [f].[FirstName] FROM [FunkyCustomers] AS [f] @@ -191,13 +191,13 @@ WHERE CAST(0 AS bit) = CAST(1 AS bit)", SELECT [f].[FirstName] FROM [FunkyCustomers] AS [f] -WHERE (@__prm4_0 = N'') OR ([f].[FirstName] IS NOT NULL AND ((LEFT([f].[FirstName], LEN(@__prm4_0)) = @__prm4_0) AND LEFT([f].[FirstName], LEN(@__prm4_0)) IS NOT NULL))", +WHERE (@__prm4_0 = N'') OR ([f].[FirstName] IS NOT NULL AND (LEFT([f].[FirstName], LEN(@__prm4_0)) = @__prm4_0))", // @"@__prm5_0='_Ba_' (Size = 4000) SELECT [f].[FirstName] FROM [FunkyCustomers] AS [f] -WHERE (@__prm5_0 = N'') OR ([f].[FirstName] IS NOT NULL AND ((LEFT([f].[FirstName], LEN(@__prm5_0)) = @__prm5_0) AND LEFT([f].[FirstName], LEN(@__prm5_0)) IS NOT NULL))", +WHERE (@__prm5_0 = N'') OR ([f].[FirstName] IS NOT NULL AND (LEFT([f].[FirstName], LEN(@__prm5_0)) = @__prm5_0))", // @"@__prm6_0='%B%a%r' (Size = 4000) @@ -237,23 +237,23 @@ WHERE [f].[FirstName] IS NOT NULL AND ([f].[FirstName] LIKE N'B\[\[a^%' ESCAPE N SELECT [f].[Id], [f].[FirstName], [f].[LastName], [f].[NullableBool] FROM [FunkyCustomers] AS [f] -WHERE (@__prm1_0 = N'') OR ([f].[FirstName] IS NOT NULL AND ((LEFT([f].[FirstName], LEN(@__prm1_0)) = @__prm1_0) AND LEFT([f].[FirstName], LEN(@__prm1_0)) IS NOT NULL))", +WHERE (@__prm1_0 = N'') OR ([f].[FirstName] IS NOT NULL AND (LEFT([f].[FirstName], LEN(@__prm1_0)) = @__prm1_0))", // @"@__prm2_0='B[' (Size = 4000) SELECT [f].[Id], [f].[FirstName], [f].[LastName], [f].[NullableBool] FROM [FunkyCustomers] AS [f] -WHERE (@__prm2_0 = N'') OR ([f].[FirstName] IS NOT NULL AND ((LEFT([f].[FirstName], LEN(@__prm2_0)) = @__prm2_0) AND LEFT([f].[FirstName], LEN(@__prm2_0)) IS NOT NULL))", +WHERE (@__prm2_0 = N'') OR ([f].[FirstName] IS NOT NULL AND (LEFT([f].[FirstName], LEN(@__prm2_0)) = @__prm2_0))", // @"@__prm3_0='B[[a^' (Size = 4000) SELECT [f].[Id], [f].[FirstName], [f].[LastName], [f].[NullableBool] FROM [FunkyCustomers] AS [f] -WHERE (@__prm3_0 = N'') OR ([f].[FirstName] IS NOT NULL AND ((LEFT([f].[FirstName], LEN(@__prm3_0)) = @__prm3_0) AND LEFT([f].[FirstName], LEN(@__prm3_0)) IS NOT NULL))", +WHERE (@__prm3_0 = N'') OR ([f].[FirstName] IS NOT NULL AND (LEFT([f].[FirstName], LEN(@__prm3_0)) = @__prm3_0))", // @"SELECT [f].[Id], [f].[FirstName], [f].[LastName], [f].[NullableBool] FROM [FunkyCustomers] AS [f] -WHERE (([f].[LastName] = N'') AND [f].[LastName] IS NOT NULL) OR ([f].[FirstName] IS NOT NULL AND ([f].[LastName] IS NOT NULL AND (LEFT([f].[FirstName], LEN([f].[LastName])) = [f].[LastName])))"); +WHERE ([f].[LastName] = N'') OR ([f].[FirstName] IS NOT NULL AND ([f].[LastName] IS NOT NULL AND (LEFT([f].[FirstName], LEN([f].[LastName])) = [f].[LastName])))"); } public override async Task String_starts_with_on_argument_with_wildcard_column(bool isAsync) @@ -264,7 +264,7 @@ public override async Task String_starts_with_on_argument_with_wildcard_column(b @"SELECT [f].[FirstName] AS [fn], [f0].[LastName] AS [ln] FROM [FunkyCustomers] AS [f] CROSS JOIN [FunkyCustomers] AS [f0] -WHERE (([f0].[LastName] = N'') AND [f0].[LastName] IS NOT NULL) OR ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND (LEFT([f].[FirstName], LEN([f0].[LastName])) = [f0].[LastName])))"); +WHERE ([f0].[LastName] = N'') OR ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND (LEFT([f].[FirstName], LEN([f0].[LastName])) = [f0].[LastName])))"); } public override async Task String_starts_with_on_argument_with_wildcard_column_negated(bool isAsync) @@ -275,7 +275,7 @@ public override async Task String_starts_with_on_argument_with_wildcard_column_n @"SELECT [f].[FirstName] AS [fn], [f0].[LastName] AS [ln] FROM [FunkyCustomers] AS [f] CROSS JOIN [FunkyCustomers] AS [f0] -WHERE (([f0].[LastName] <> N'') OR [f0].[LastName] IS NULL) AND ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND (LEFT([f].[FirstName], LEN([f0].[LastName])) <> [f0].[LastName])))"); +WHERE (([f0].[LastName] <> N'') OR [f0].[LastName] IS NULL) AND ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND ((LEFT([f].[FirstName], LEN([f0].[LastName])) <> [f0].[LastName]) OR LEFT([f].[FirstName], LEN([f0].[LastName])) IS NULL)))"); } public override async Task String_ends_with_on_argument_with_wildcard_constant(bool isAsync) @@ -324,13 +324,13 @@ public override async Task String_ends_with_on_argument_with_wildcard_parameter( SELECT [f].[FirstName] FROM [FunkyCustomers] AS [f] -WHERE (@__prm1_0 = N'') OR ([f].[FirstName] IS NOT NULL AND ((RIGHT([f].[FirstName], LEN(@__prm1_0)) = @__prm1_0) AND RIGHT([f].[FirstName], LEN(@__prm1_0)) IS NOT NULL))", +WHERE (@__prm1_0 = N'') OR ([f].[FirstName] IS NOT NULL AND (RIGHT([f].[FirstName], LEN(@__prm1_0)) = @__prm1_0))", // @"@__prm2_0='a_' (Size = 4000) SELECT [f].[FirstName] FROM [FunkyCustomers] AS [f] -WHERE (@__prm2_0 = N'') OR ([f].[FirstName] IS NOT NULL AND ((RIGHT([f].[FirstName], LEN(@__prm2_0)) = @__prm2_0) AND RIGHT([f].[FirstName], LEN(@__prm2_0)) IS NOT NULL))", +WHERE (@__prm2_0 = N'') OR ([f].[FirstName] IS NOT NULL AND (RIGHT([f].[FirstName], LEN(@__prm2_0)) = @__prm2_0))", // @"SELECT [f].[FirstName] FROM [FunkyCustomers] AS [f] @@ -340,13 +340,13 @@ WHERE CAST(0 AS bit) = CAST(1 AS bit)", SELECT [f].[FirstName] FROM [FunkyCustomers] AS [f] -WHERE (@__prm4_0 = N'') OR ([f].[FirstName] IS NOT NULL AND ((RIGHT([f].[FirstName], LEN(@__prm4_0)) = @__prm4_0) AND RIGHT([f].[FirstName], LEN(@__prm4_0)) IS NOT NULL))", +WHERE (@__prm4_0 = N'') OR ([f].[FirstName] IS NOT NULL AND (RIGHT([f].[FirstName], LEN(@__prm4_0)) = @__prm4_0))", // @"@__prm5_0='_Ba_' (Size = 4000) SELECT [f].[FirstName] FROM [FunkyCustomers] AS [f] -WHERE (@__prm5_0 = N'') OR ([f].[FirstName] IS NOT NULL AND ((RIGHT([f].[FirstName], LEN(@__prm5_0)) = @__prm5_0) AND RIGHT([f].[FirstName], LEN(@__prm5_0)) IS NOT NULL))", +WHERE (@__prm5_0 = N'') OR ([f].[FirstName] IS NOT NULL AND (RIGHT([f].[FirstName], LEN(@__prm5_0)) = @__prm5_0))", // @"@__prm6_0='%B%a%r' (Size = 4000) @@ -373,7 +373,7 @@ public override async Task String_ends_with_on_argument_with_wildcard_column(boo @"SELECT [f].[FirstName] AS [fn], [f0].[LastName] AS [ln] FROM [FunkyCustomers] AS [f] CROSS JOIN [FunkyCustomers] AS [f0] -WHERE (([f0].[LastName] = N'') AND [f0].[LastName] IS NOT NULL) OR ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND (RIGHT([f].[FirstName], LEN([f0].[LastName])) = [f0].[LastName])))"); +WHERE ([f0].[LastName] = N'') OR ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND (RIGHT([f].[FirstName], LEN([f0].[LastName])) = [f0].[LastName])))"); } public override async Task String_ends_with_on_argument_with_wildcard_column_negated(bool isAsync) @@ -384,7 +384,7 @@ public override async Task String_ends_with_on_argument_with_wildcard_column_neg @"SELECT [f].[FirstName] AS [fn], [f0].[LastName] AS [ln] FROM [FunkyCustomers] AS [f] CROSS JOIN [FunkyCustomers] AS [f0] -WHERE (([f0].[LastName] <> N'') OR [f0].[LastName] IS NULL) AND ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND (RIGHT([f].[FirstName], LEN([f0].[LastName])) <> [f0].[LastName])))"); +WHERE (([f0].[LastName] <> N'') OR [f0].[LastName] IS NULL) AND ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND ((RIGHT([f].[FirstName], LEN([f0].[LastName])) <> [f0].[LastName]) OR RIGHT([f].[FirstName], LEN([f0].[LastName])) IS NULL)))"); } public override async Task String_ends_with_inside_conditional(bool isAsync) @@ -396,7 +396,7 @@ public override async Task String_ends_with_inside_conditional(bool isAsync) FROM [FunkyCustomers] AS [f] CROSS JOIN [FunkyCustomers] AS [f0] WHERE CASE - WHEN (([f0].[LastName] = N'') AND [f0].[LastName] IS NOT NULL) OR ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND (RIGHT([f].[FirstName], LEN([f0].[LastName])) = [f0].[LastName]))) THEN CAST(1 AS bit) + WHEN ([f0].[LastName] = N'') OR ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND (RIGHT([f].[FirstName], LEN([f0].[LastName])) = [f0].[LastName]))) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END = CAST(1 AS bit)"); } @@ -410,7 +410,7 @@ public override async Task String_ends_with_inside_conditional_negated(bool isAs FROM [FunkyCustomers] AS [f] CROSS JOIN [FunkyCustomers] AS [f0] WHERE CASE - WHEN (([f0].[LastName] <> N'') OR [f0].[LastName] IS NULL) AND ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND (RIGHT([f].[FirstName], LEN([f0].[LastName])) <> [f0].[LastName]))) THEN CAST(1 AS bit) + WHEN (([f0].[LastName] <> N'') OR [f0].[LastName] IS NULL) AND ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND ((RIGHT([f].[FirstName], LEN([f0].[LastName])) <> [f0].[LastName]) OR RIGHT([f].[FirstName], LEN([f0].[LastName])) IS NULL))) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END = CAST(1 AS bit)"); } @@ -423,10 +423,10 @@ public override async Task String_ends_with_equals_nullable_column(bool isAsync) @"SELECT [f].[Id], [f].[FirstName], [f].[LastName], [f].[NullableBool], [f0].[Id], [f0].[FirstName], [f0].[LastName], [f0].[NullableBool] FROM [FunkyCustomers] AS [f] CROSS JOIN [FunkyCustomers] AS [f0] -WHERE (CASE - WHEN (([f0].[LastName] = N'') AND [f0].[LastName] IS NOT NULL) OR ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND (RIGHT([f].[FirstName], LEN([f0].[LastName])) = [f0].[LastName]))) THEN CAST(1 AS bit) +WHERE CASE + WHEN (([f0].[LastName] = N'') AND [f0].[LastName] IS NOT NULL) OR ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND ((RIGHT([f].[FirstName], LEN([f0].[LastName])) = [f0].[LastName]) AND RIGHT([f].[FirstName], LEN([f0].[LastName])) IS NOT NULL))) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) -END = [f].[NullableBool]) AND [f].[NullableBool] IS NOT NULL"); +END = [f].[NullableBool]"); } public override async Task String_ends_with_not_equals_nullable_column(bool isAsync) @@ -438,7 +438,7 @@ public override async Task String_ends_with_not_equals_nullable_column(bool isAs FROM [FunkyCustomers] AS [f] CROSS JOIN [FunkyCustomers] AS [f0] WHERE (CASE - WHEN (([f0].[LastName] = N'') AND [f0].[LastName] IS NOT NULL) OR ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND (RIGHT([f].[FirstName], LEN([f0].[LastName])) = [f0].[LastName]))) THEN CAST(1 AS bit) + WHEN (([f0].[LastName] = N'') AND [f0].[LastName] IS NOT NULL) OR ([f].[FirstName] IS NOT NULL AND ([f0].[LastName] IS NOT NULL AND ((RIGHT([f].[FirstName], LEN([f0].[LastName])) = [f0].[LastName]) AND RIGHT([f].[FirstName], LEN([f0].[LastName])) IS NOT NULL))) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END <> [f].[NullableBool]) OR [f].[NullableBool] IS NULL"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index 7e3f37a8980..9c45d62ab35 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -42,7 +42,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN [Weapons] AS [w] ON [t0].[FullName] = [w].[OwnerFullName] ORDER BY [t].[Id], [w].[Id]"); } @@ -58,7 +58,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN [Squads] AS [s] ON [t0].[SquadId] = [s].[Id]"); } @@ -119,7 +119,7 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t] ON (([g].[Nickname] = [t].[LeaderNickname]) AND [t].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t].[LeaderSquadId]) +) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); } @@ -135,7 +135,7 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t] ON (([g].[Nickname] = [t].[LeaderNickname]) AND [t].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t].[LeaderSquadId]) +) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); } @@ -151,8 +151,8 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) -WHERE ([t0].[Nickname] = N'Marcus') AND [t0].[Nickname] IS NOT NULL"); +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) +WHERE [t0].[Nickname] = N'Marcus'"); } public override async Task Include_with_join_reference1(bool isAsync) @@ -162,7 +162,7 @@ public override async Task Include_with_join_reference1(bool isAsync) AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [c].[Name], [c].[Location], [c].[Nation] FROM [Gears] AS [g] -INNER JOIN [Tags] AS [t] ON (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) AND (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) +INNER JOIN [Tags] AS [t] ON ([g].[SquadId] = [t].[GearSquadId]) AND ([g].[Nickname] = [t].[GearNickName]) INNER JOIN [Cities] AS [c] ON [g].[CityOfBirthName] = [c].[Name] WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); } @@ -178,7 +178,7 @@ INNER JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) AND (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) +) AS [t0] ON ([t].[GearSquadId] = [t0].[SquadId]) AND ([t].[GearNickName] = [t0].[Nickname]) INNER JOIN [Cities] AS [c] ON [t0].[CityOfBirthName] = [c].[Name]"); } @@ -189,7 +189,7 @@ public override async Task Include_with_join_collection1(bool isAsync) AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [t].[Id], [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Gears] AS [g] -INNER JOIN [Tags] AS [t] ON (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) AND (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) +INNER JOIN [Tags] AS [t] ON ([g].[SquadId] = [t].[GearSquadId]) AND ([g].[Nickname] = [t].[GearNickName]) LEFT JOIN [Weapons] AS [w] ON [g].[FullName] = [w].[OwnerFullName] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [t].[Id], [w].[Id]"); @@ -206,7 +206,7 @@ INNER JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) AND (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) +) AS [t0] ON ([t].[GearSquadId] = [t0].[SquadId]) AND ([t].[GearNickName] = [t0].[Nickname]) LEFT JOIN [Weapons] AS [w] ON [t0].[FullName] = [w].[OwnerFullName] ORDER BY [t].[Id], [t0].[Nickname], [t0].[SquadId], [w].[Id]"); } @@ -221,7 +221,7 @@ public override async Task Include_where_list_contains_navigation(bool isAsync) // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[Note] FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([t].[Id] IS NOT NULL AND [t].[Id] IN ('34c8d86e-a4ac-4be5-827f-584dda348a07', 'df36f493-463f-4123-83f9-6b135deeb7ba', 'a8ad98f9-e023-4e2a-9a70-c2728455bd34', '70534e05-782c-4052-8720-c2c54481ce5f', 'a7be028a-0cf2-448f-ab55-ce8bc5d8cf69', 'b39a6fba-9026-4d69-828e-fd7068673e57'))"); } @@ -236,7 +236,7 @@ public override async Task Include_where_list_contains_navigation2(bool isAsync) @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[Note] FROM [Gears] AS [g] INNER JOIN [Cities] AS [c] ON [g].[CityOfBirthName] = [c].[Name] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([c].[Location] IS NOT NULL AND [t].[Id] IN ('34c8d86e-a4ac-4be5-827f-584dda348a07', 'df36f493-463f-4123-83f9-6b135deeb7ba', 'a8ad98f9-e023-4e2a-9a70-c2728455bd34', '70534e05-782c-4052-8720-c2c54481ce5f', 'a7be028a-0cf2-448f-ab55-ce8bc5d8cf69', 'b39a6fba-9026-4d69-828e-fd7068673e57'))"); } @@ -247,9 +247,10 @@ public override async Task Navigation_accessed_twice_outside_and_inside_subquery AssertSql( @"SELECT [t].[Id] FROM [Tags] AS [t]", + // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([t].[Id] IS NOT NULL AND [t].[Id] IN ('34c8d86e-a4ac-4be5-827f-584dda348a07', 'df36f493-463f-4123-83f9-6b135deeb7ba', 'a8ad98f9-e023-4e2a-9a70-c2728455bd34', '70534e05-782c-4052-8720-c2c54481ce5f', 'a7be028a-0cf2-448f-ab55-ce8bc5d8cf69', 'b39a6fba-9026-4d69-828e-fd7068673e57'))"); } @@ -260,7 +261,7 @@ public override async Task Include_with_join_multi_level(bool isAsync) AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [c].[Name], [c].[Location], [c].[Nation], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t0].[AssignedCityName], [t0].[CityOfBirthName], [t0].[Discriminator], [t0].[FullName], [t0].[HasSoulPatch], [t0].[LeaderNickname], [t0].[LeaderSquadId], [t0].[Rank] FROM [Gears] AS [g] -INNER JOIN [Tags] AS [t] ON (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) AND (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) +INNER JOIN [Tags] AS [t] ON ([g].[SquadId] = [t].[GearSquadId]) AND ([g].[Nickname] = [t].[GearNickName]) INNER JOIN [Cities] AS [c] ON [g].[CityOfBirthName] = [c].[Name] LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[Discriminator], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank] @@ -282,7 +283,7 @@ INNER JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') -) AS [t0] ON (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) AND (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) +) AS [t0] ON ([t].[GearSquadId] = [t0].[SquadId]) AND ([t].[GearNickName] = [t0].[Nickname]) INNER JOIN [Cities] AS [c] ON [t0].[CityOfBirthName] = [c].[Name]"); } @@ -297,12 +298,12 @@ INNER JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') -) AS [t0] ON (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) AND (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) +) AS [t0] ON ([t].[GearSquadId] = [t0].[SquadId]) AND ([t].[GearNickName] = [t0].[Nickname]) LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t1].[LeaderNickname] IS NOT NULL) AND ([t0].[SquadId] = [t1].[LeaderSquadId]) +) AS [t1] ON ([t0].[Nickname] = [t1].[LeaderNickname]) AND ([t0].[SquadId] = [t1].[LeaderSquadId]) ORDER BY [t0].[HasSoulPatch], [t0].[Nickname] DESC, [t].[Id], [t0].[SquadId], [t1].[Nickname], [t1].[SquadId]"); } @@ -313,7 +314,7 @@ public override async Task Include_with_join_and_inheritance2(bool isAsync) AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [t].[Id], [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Gears] AS [g] -INNER JOIN [Tags] AS [t] ON (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) AND (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) +INNER JOIN [Tags] AS [t] ON ([g].[SquadId] = [t].[GearSquadId]) AND ([g].[Nickname] = [t].[GearNickName]) LEFT JOIN [Weapons] AS [w] ON [g].[FullName] = [w].[OwnerFullName] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [t].[Id], [w].[Id]"); @@ -330,12 +331,12 @@ INNER JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') -) AS [t0] ON (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) AND (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) +) AS [t0] ON ([t].[GearSquadId] = [t0].[SquadId]) AND ([t].[GearNickName] = [t0].[Nickname]) LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t1].[LeaderNickname] IS NOT NULL) AND ([t0].[SquadId] = [t1].[LeaderSquadId]) +) AS [t1] ON ([t0].[Nickname] = [t1].[LeaderNickname]) AND ([t0].[SquadId] = [t1].[LeaderSquadId]) ORDER BY [t].[Id], [t0].[Nickname], [t0].[SquadId], [t1].[Nickname], [t1].[SquadId]"); } @@ -373,7 +374,7 @@ public override async Task Where_nullable_enum_with_constant(bool isAsync) AssertSql( @"SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] -WHERE ([w].[AmmunitionType] = 1) AND [w].[AmmunitionType] IS NOT NULL"); +WHERE [w].[AmmunitionType] = 1"); } public override async Task Where_nullable_enum_with_null_constant(bool isAsync) @@ -395,7 +396,7 @@ public override async Task Where_nullable_enum_with_non_nullable_parameter(bool SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] -WHERE ([w].[AmmunitionType] = @__ammunitionType_0) AND [w].[AmmunitionType] IS NOT NULL"); +WHERE [w].[AmmunitionType] = @__ammunitionType_0"); } public override async Task Where_nullable_enum_with_nullable_parameter(bool isAsync) @@ -407,7 +408,7 @@ public override async Task Where_nullable_enum_with_nullable_parameter(bool isAs SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] -WHERE ([w].[AmmunitionType] = @__ammunitionType_0) AND [w].[AmmunitionType] IS NOT NULL", +WHERE [w].[AmmunitionType] = @__ammunitionType_0", // @"SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] @@ -555,7 +556,7 @@ public override async Task Where_enum_has_flag_subquery(bool isAsync) AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (((([g].[Rank] & ( +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ((([g].[Rank] & ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') @@ -563,15 +564,7 @@ WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId])) AND (( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL AND ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL)) OR (( + ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ([g].[Rank] & ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') @@ -583,7 +576,7 @@ WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ((((1 & ( +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (((1 & ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') @@ -591,15 +584,7 @@ WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId])) AND (( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL AND ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL)) OR (( + ORDER BY [g0].[Nickname], [g0].[SquadId])) OR (1 & ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') @@ -617,7 +602,7 @@ public override async Task Where_enum_has_flag_subquery_with_pushdown(bool isAsy AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (((([g].[Rank] & ( +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ((([g].[Rank] & ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') @@ -625,15 +610,7 @@ WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId])) AND (( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL AND ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL)) OR (( + ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ([g].[Rank] & ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') @@ -645,7 +622,7 @@ WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ((((1 & ( +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (((1 & ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') @@ -653,15 +630,7 @@ WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId])) AND (( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL AND ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL)) OR (( + ORDER BY [g0].[Nickname], [g0].[SquadId])) OR (1 & ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') @@ -679,7 +648,7 @@ public override async Task Where_enum_has_flag_subquery_client_eval(bool isAsync AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (((([g].[Rank] & ( +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ((([g].[Rank] & ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') @@ -687,15 +656,7 @@ WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId])) AND (( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL AND ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL)) OR (( + ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ([g].[Rank] & ( SELECT TOP(1) [g0].[Rank] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') @@ -753,13 +714,10 @@ public override async Task Where_count_subquery_without_collision(bool isAsync) AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ((( - SELECT COUNT(*) - FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) = 2) AND ( +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (( SELECT COUNT(*) FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) IS NOT NULL)"); + WHERE [g].[FullName] = [w].[OwnerFullName]) = 2)"); } public override async Task Where_any_subquery_without_collision(bool isAsync) @@ -772,7 +730,7 @@ FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND EXISTS ( SELECT 1 FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL)"); + WHERE [g].[FullName] = [w].[OwnerFullName])"); } public override async Task Select_inverted_boolean(bool isAsync) @@ -800,7 +758,7 @@ public override async Task Select_comparison_with_null(bool isAsync) ELSE CAST(0 AS bit) END AS [Cartridge] FROM [Weapons] AS [w] -WHERE ([w].[AmmunitionType] = @__ammunitionType_0) AND [w].[AmmunitionType] IS NOT NULL", +WHERE [w].[AmmunitionType] = @__ammunitionType_0", // @"SELECT [w].[Id], CASE WHEN [w].[AmmunitionType] IS NULL THEN CAST(1 AS bit) @@ -866,11 +824,11 @@ public override async Task Select_ternary_operation_with_has_value_not_null(bool AssertSql( @"SELECT [w].[Id], CASE - WHEN [w].[AmmunitionType] IS NOT NULL AND (([w].[AmmunitionType] = 1) AND [w].[AmmunitionType] IS NOT NULL) THEN N'Yes' + WHEN [w].[AmmunitionType] IS NOT NULL AND ([w].[AmmunitionType] = 1) THEN N'Yes' ELSE N'No' END AS [IsCartridge] FROM [Weapons] AS [w] -WHERE [w].[AmmunitionType] IS NOT NULL AND (([w].[AmmunitionType] = 1) AND [w].[AmmunitionType] IS NOT NULL)"); +WHERE [w].[AmmunitionType] IS NOT NULL AND ([w].[AmmunitionType] = 1)"); } public override async Task Select_ternary_operation_multiple_conditions(bool isAsync) @@ -879,7 +837,7 @@ public override async Task Select_ternary_operation_multiple_conditions(bool isA AssertSql( @"SELECT [w].[Id], CASE - WHEN (([w].[AmmunitionType] = 2) AND [w].[AmmunitionType] IS NOT NULL) AND (([w].[SynergyWithId] = 1) AND [w].[SynergyWithId] IS NOT NULL) THEN N'Yes' + WHEN ([w].[AmmunitionType] = 2) AND ([w].[SynergyWithId] = 1) THEN N'Yes' ELSE N'No' END AS [IsCartridge] FROM [Weapons] AS [w]"); @@ -891,7 +849,7 @@ public override async Task Select_ternary_operation_multiple_conditions_2(bool i AssertSql( @"SELECT [w].[Id], CASE - WHEN ([w].[IsAutomatic] <> CAST(1 AS bit)) AND (([w].[SynergyWithId] = 1) AND [w].[SynergyWithId] IS NOT NULL) THEN N'Yes' + WHEN ([w].[IsAutomatic] <> CAST(1 AS bit)) AND ([w].[SynergyWithId] = 1) THEN N'Yes' ELSE N'No' END AS [IsCartridge] FROM [Weapons] AS [w]"); @@ -916,7 +874,7 @@ public override async Task Select_nested_ternary_operations(bool isAsync) AssertSql( @"SELECT [w].[Id], CASE WHEN [w].[IsAutomatic] <> CAST(1 AS bit) THEN CASE - WHEN ([w].[AmmunitionType] = 1) AND [w].[AmmunitionType] IS NOT NULL THEN N'ManualCartridge' + WHEN [w].[AmmunitionType] = 1 THEN N'ManualCartridge' ELSE N'Manual' END ELSE N'Auto' @@ -931,7 +889,10 @@ public override async Task Null_propagation_optimization1(bool isAsync) AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[LeaderNickname] = N'Marcus') AND [g].[LeaderNickname] IS NOT NULL)"); +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (CASE + WHEN ([g].[LeaderNickname] = N'Marcus') AND [g].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END = CAST(1 AS bit))"); } public override async Task Null_propagation_optimization2(bool isAsync) @@ -1027,7 +988,7 @@ public override async Task Select_null_propagation_negative1(bool isAsync) AssertSql( @"SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CASE - WHEN CAST(LEN([g].[Nickname]) AS int) = 5 THEN CAST(1 AS bit) + WHEN (CAST(LEN([g].[Nickname]) AS int) = 5) AND LEN([g].[Nickname]) IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END ELSE NULL @@ -1121,7 +1082,7 @@ public override async Task Select_null_propagation_negative6(bool isAsync) AssertSql( @"SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CASE - WHEN ((CAST(LEN([g].[LeaderNickname]) AS int) <> CAST(LEN([g].[LeaderNickname]) AS int)) OR (LEN([g].[LeaderNickname]) IS NULL OR LEN([g].[LeaderNickname]) IS NULL)) AND (LEN([g].[LeaderNickname]) IS NOT NULL OR LEN([g].[LeaderNickname]) IS NOT NULL) THEN CAST(1 AS bit) + WHEN ((CAST(LEN([g].[LeaderNickname]) AS int) <> CAST(LEN([g].[LeaderNickname]) AS int)) OR LEN([g].[LeaderNickname]) IS NULL) AND LEN([g].[LeaderNickname]) IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END ELSE NULL @@ -1137,7 +1098,7 @@ public override async Task Select_null_propagation_negative7(bool isAsync) AssertSql( @"SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CASE - WHEN (([g].[LeaderNickname] = [g].[LeaderNickname]) AND ([g].[LeaderNickname] IS NOT NULL AND [g].[LeaderNickname] IS NOT NULL)) OR ([g].[LeaderNickname] IS NULL AND [g].[LeaderNickname] IS NULL) THEN CAST(1 AS bit) + WHEN (([g].[LeaderNickname] = [g].[LeaderNickname]) AND [g].[LeaderNickname] IS NOT NULL) OR [g].[LeaderNickname] IS NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END ELSE NULL @@ -1160,7 +1121,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN [Squads] AS [s] ON [t0].[SquadId] = [s].[Id] LEFT JOIN [Cities] AS [c] ON [t0].[AssignedCityName] = [c].[Name]"); } @@ -1176,7 +1137,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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)"); +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId])"); } public override async Task Select_null_propagation_works_for_multiple_navigations_with_composite_keys(bool isAsync) @@ -1193,13 +1154,13 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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 [Tags] AS [t1] ON ((([t0].[Nickname] = [t1].[GearNickName]) AND ([t0].[Nickname] IS NOT NULL AND [t1].[GearNickName] IS NOT NULL)) OR ([t0].[Nickname] IS NULL AND [t1].[GearNickName] IS NULL)) AND ((([t0].[SquadId] = [t1].[GearSquadId]) AND ([t0].[SquadId] IS NOT NULL AND [t1].[GearSquadId] IS NOT NULL)) OR ([t0].[SquadId] IS NULL AND [t1].[GearSquadId] IS NULL)) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) +LEFT JOIN [Tags] AS [t1] ON (([t0].[Nickname] = [t1].[GearNickName]) OR ([t0].[Nickname] IS NULL AND [t1].[GearNickName] IS NULL)) AND (([t0].[SquadId] = [t1].[GearSquadId]) OR ([t0].[SquadId] IS NULL AND [t1].[GearSquadId] IS NULL)) LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t2] ON (([t1].[GearNickName] = [t2].[Nickname]) AND [t1].[GearNickName] IS NOT NULL) AND (([t1].[GearSquadId] = [t2].[SquadId]) AND [t1].[GearSquadId] IS NOT NULL) +) AS [t2] ON ([t1].[GearNickName] = [t2].[Nickname]) AND ([t1].[GearSquadId] = [t2].[SquadId]) LEFT JOIN [Cities] AS [c] ON [t2].[AssignedCityName] = [c].[Name]"); } @@ -1257,7 +1218,7 @@ public override async Task Where_member_access_on_anonymous_type(bool isAsync) AssertSql( @"SELECT [g].[Nickname] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[LeaderNickname] = N'Marcus') AND [g].[LeaderNickname] IS NOT NULL)"); +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[LeaderNickname] = N'Marcus')"); } public override async Task Where_compare_anonymous_types_with_uncorrelated_members(bool isAsync) @@ -1282,13 +1243,13 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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 [t1] ON (([t].[GearNickName] = [t1].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t1].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) +) AS [t1] ON ([t].[GearNickName] = [t1].[Nickname]) AND ([t].[GearSquadId] = [t1].[SquadId]) LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t2] ON (([t0].[GearNickName] = [t2].[Nickname]) AND [t0].[GearNickName] IS NOT NULL) AND (([t0].[GearSquadId] = [t2].[SquadId]) AND [t0].[GearSquadId] IS NOT NULL) -WHERE (([t1].[Nickname] = [t2].[Nickname]) AND ([t1].[Nickname] IS NOT NULL AND [t2].[Nickname] IS NOT NULL)) OR ([t1].[Nickname] IS NULL AND [t2].[Nickname] IS NULL)"); +) AS [t2] ON ([t0].[GearNickName] = [t2].[Nickname]) AND ([t0].[GearSquadId] = [t2].[SquadId]) +WHERE ([t1].[Nickname] = [t2].[Nickname]) OR ([t1].[Nickname] IS NULL AND [t2].[Nickname] IS NULL)"); } public override async Task Select_Singleton_Navigation_With_Member_Access(bool isAsync) @@ -1302,8 +1263,8 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) -WHERE (([t0].[Nickname] = N'Marcus') AND [t0].[Nickname] IS NOT NULL) AND (([t0].[CityOfBirthName] <> N'Ephyra') OR [t0].[CityOfBirthName] IS NULL)"); +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) +WHERE ([t0].[Nickname] = N'Marcus') AND (([t0].[CityOfBirthName] <> N'Ephyra') OR [t0].[CityOfBirthName] IS NULL)"); } public override async Task Select_Where_Navigation(bool isAsync) @@ -1317,8 +1278,8 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) -WHERE ([t0].[Nickname] = N'Marcus') AND [t0].[Nickname] IS NOT NULL"); +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) +WHERE [t0].[Nickname] = N'Marcus'"); } public override async Task Select_Where_Navigation_Equals_Navigation(bool isAsync) @@ -1333,13 +1294,13 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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 [t1] ON (([t].[GearNickName] = [t1].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t1].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) +) AS [t1] ON ([t].[GearNickName] = [t1].[Nickname]) AND ([t].[GearSquadId] = [t1].[SquadId]) LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t2] ON (([t0].[GearNickName] = [t2].[Nickname]) AND [t0].[GearNickName] IS NOT NULL) AND (([t0].[GearSquadId] = [t2].[SquadId]) AND [t0].[GearSquadId] IS NOT NULL) -WHERE ((([t1].[Nickname] = [t2].[Nickname]) AND ([t1].[Nickname] IS NOT NULL AND [t2].[Nickname] IS NOT NULL)) OR ([t1].[Nickname] IS NULL AND [t2].[Nickname] IS NULL)) AND ((([t1].[SquadId] = [t2].[SquadId]) AND ([t1].[SquadId] IS NOT NULL AND [t2].[SquadId] IS NOT NULL)) OR ([t1].[SquadId] IS NULL AND [t2].[SquadId] IS NULL))"); +) AS [t2] ON ([t0].[GearNickName] = [t2].[Nickname]) AND ([t0].[GearSquadId] = [t2].[SquadId]) +WHERE (([t1].[Nickname] = [t2].[Nickname]) OR ([t1].[Nickname] IS NULL AND [t2].[Nickname] IS NULL)) AND (([t1].[SquadId] = [t2].[SquadId]) OR ([t1].[SquadId] IS NULL AND [t2].[SquadId] IS NULL))"); } public override async Task Select_Where_Navigation_Null(bool isAsync) @@ -1353,7 +1314,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE [t0].[Nickname] IS NULL"); } @@ -1368,7 +1329,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE [t0].[Nickname] IS NULL"); } @@ -1384,13 +1345,13 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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 [t1] ON (([t].[GearNickName] = [t1].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t1].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) +) AS [t1] ON ([t].[GearNickName] = [t1].[Nickname]) AND ([t].[GearSquadId] = [t1].[SquadId]) LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t2] ON (([t0].[GearNickName] = [t2].[Nickname]) AND [t0].[GearNickName] IS NOT NULL) AND (([t0].[GearSquadId] = [t2].[SquadId]) AND [t0].[GearSquadId] IS NOT NULL) -WHERE (([t1].[Nickname] = [t2].[Nickname]) AND ([t1].[Nickname] IS NOT NULL AND [t2].[Nickname] IS NOT NULL)) OR ([t1].[Nickname] IS NULL AND [t2].[Nickname] IS NULL)"); +) AS [t2] ON ([t0].[GearNickName] = [t2].[Nickname]) AND ([t0].[GearSquadId] = [t2].[SquadId]) +WHERE ([t1].[Nickname] = [t2].[Nickname]) OR ([t1].[Nickname] IS NULL AND [t2].[Nickname] IS NULL)"); } public override async Task Optional_Navigation_Null_Coalesce_To_Clr_Type(bool isAsync) @@ -1414,7 +1375,7 @@ FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (( SELECT TOP(1) [w].[IsAutomatic] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ORDER BY [w].[Id]) = CAST(1 AS bit))"); } @@ -1428,7 +1389,7 @@ FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (( SELECT TOP(1) [w].[IsAutomatic] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ORDER BY [w].[Id]) = CAST(1 AS bit))"); } @@ -1444,7 +1405,7 @@ SELECT TOP(1) [t].[IsAutomatic] FROM ( SELECT DISTINCT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ) AS [t] ORDER BY [t].[Id]) = CAST(1 AS bit)))"); } @@ -1461,7 +1422,7 @@ SELECT TOP(1) [t].[IsAutomatic] FROM ( SELECT DISTINCT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ) AS [t] ORDER BY [t].[Id]) = CAST(1 AS bit)))"); } @@ -1478,7 +1439,7 @@ SELECT TOP(1) [t].[IsAutomatic] FROM ( SELECT DISTINCT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ) AS [t] ORDER BY [t].[Id]) = CAST(1 AS bit))) ORDER BY [g].[Nickname]"); @@ -1496,7 +1457,7 @@ SELECT TOP(1) [t].[IsAutomatic] FROM ( SELECT DISTINCT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND (CHARINDEX(N'Lancer', [w].[Name]) > 0) + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND (CHARINDEX(N'Lancer', [w].[Name]) > 0) ) AS [t]) = CAST(1 AS bit))) ORDER BY [g].[Nickname]"); } @@ -1511,7 +1472,7 @@ FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[HasSoulPatch] = CAST(1 AS bit)) AND (( SELECT DISTINCT TOP(1) [w].[IsAutomatic] FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND (CHARINDEX(N'Lancer', [w].[Name]) > 0)) = CAST(1 AS bit))) + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND (CHARINDEX(N'Lancer', [w].[Name]) > 0)) = CAST(1 AS bit))) ORDER BY [g].[Nickname]"); } @@ -1527,7 +1488,7 @@ SELECT TOP(1) [t].[IsAutomatic] FROM ( SELECT DISTINCT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND (CHARINDEX(N'Lancer', [w].[Name]) > 0) + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND (CHARINDEX(N'Lancer', [w].[Name]) > 0) ) AS [t]) = CAST(1 AS bit))) ORDER BY [g].[Nickname]"); } @@ -1544,7 +1505,7 @@ SELECT TOP(1) [t].[IsAutomatic] FROM ( SELECT DISTINCT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ) AS [t] ORDER BY [t].[Id] DESC) <> CAST(1 AS bit)) ORDER BY [g].[Nickname]"); @@ -1562,7 +1523,7 @@ SELECT TOP(1) [t].[IsAutomatic] FROM ( SELECT DISTINCT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ) AS [t] ORDER BY [t].[Id] DESC) = CAST(1 AS bit))) ORDER BY [g].[Nickname]"); @@ -1580,7 +1541,7 @@ SELECT TOP(1) [t].[IsAutomatic] FROM ( SELECT DISTINCT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ) AS [t] ORDER BY [t].[Id]) = CAST(1 AS bit)))"); } @@ -1597,7 +1558,7 @@ SELECT TOP(1) [t].[IsAutomatic] FROM ( SELECT DISTINCT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ) AS [t] ORDER BY [t].[Id]) = CAST(1 AS bit)))"); } @@ -1730,7 +1691,7 @@ SELECT TOP(1) [t].[Name] FROM ( SELECT DISTINCT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ) AS [t] ORDER BY [t].[Id]) FROM [Gears] AS [g] @@ -1748,8 +1709,8 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) -WHERE (([t0].[Nickname] = N'Marcus') AND [t0].[Nickname] IS NOT NULL) AND (([t0].[CityOfBirthName] <> N'Ephyra') OR [t0].[CityOfBirthName] IS NULL)"); +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) +WHERE ([t0].[Nickname] = N'Marcus') AND (([t0].[CityOfBirthName] <> N'Ephyra') OR [t0].[CityOfBirthName] IS NULL)"); } public override async Task GroupJoin_Composite_Key(bool isAsync) @@ -1763,7 +1724,7 @@ INNER JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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)"); +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId])"); } public override async Task Join_navigation_translated_to_subquery_composite_key(bool isAsync) @@ -1780,7 +1741,7 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t0] ON (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) + ) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) ) AS [t1] ON [g].[FullName] = [t1].[FullName] WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); } @@ -1799,7 +1760,7 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t0] ON (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) + ) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) ) AS [t1] ON [g].[FullName] = [t1].[FullName] WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); } @@ -1847,8 +1808,8 @@ INNER JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') -) AS [t0] ON (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) AND (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) -LEFT JOIN [Tags] AS [t1] ON (([t0].[Nickname] = [t1].[GearNickName]) AND [t1].[GearNickName] IS NOT NULL) AND (([t0].[SquadId] = [t1].[GearSquadId]) AND [t1].[GearSquadId] IS NOT NULL)"); +) AS [t0] ON ([t].[GearSquadId] = [t0].[SquadId]) AND ([t].[GearNickName] = [t0].[Nickname]) +LEFT JOIN [Tags] AS [t1] ON ([t0].[Nickname] = [t1].[GearNickName]) AND ([t0].[SquadId] = [t1].[GearSquadId])"); } public override async Task Collection_with_inheritance_and_join_include_source(bool isAsync) @@ -1858,8 +1819,8 @@ public override async Task Collection_with_inheritance_and_join_include_source(b AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [t0].[Id], [t0].[GearNickName], [t0].[GearSquadId], [t0].[Note] FROM [Gears] AS [g] -INNER JOIN [Tags] AS [t] ON (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) AND (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) -LEFT JOIN [Tags] AS [t0] ON (([g].[Nickname] = [t0].[GearNickName]) AND [t0].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t0].[GearSquadId]) AND [t0].[GearSquadId] IS NOT NULL) +INNER JOIN [Tags] AS [t] ON ([g].[SquadId] = [t].[GearSquadId]) AND ([g].[Nickname] = [t].[GearNickName]) +LEFT JOIN [Tags] AS [t0] ON ([g].[Nickname] = [t0].[GearNickName]) AND ([g].[SquadId] = [t0].[GearSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer')"); } @@ -1870,7 +1831,7 @@ public override async Task Non_unicode_string_literal_is_used_for_non_unicode_co AssertSql( @"SELECT [c].[Name], [c].[Location], [c].[Nation] FROM [Cities] AS [c] -WHERE ([c].[Location] = 'Unknown') AND [c].[Location] IS NOT NULL"); +WHERE [c].[Location] = 'Unknown'"); } public override async Task Non_unicode_string_literal_is_used_for_non_unicode_column_right(bool isAsync) @@ -1880,7 +1841,7 @@ public override async Task Non_unicode_string_literal_is_used_for_non_unicode_co AssertSql( @"SELECT [c].[Name], [c].[Location], [c].[Nation] FROM [Cities] AS [c] -WHERE ('Unknown' = [c].[Location]) AND [c].[Location] IS NOT NULL"); +WHERE 'Unknown' = [c].[Location]"); } public override async Task Non_unicode_parameter_is_used_for_non_unicode_column(bool isAsync) @@ -1892,7 +1853,7 @@ public override async Task Non_unicode_parameter_is_used_for_non_unicode_column( SELECT [c].[Name], [c].[Location], [c].[Nation] FROM [Cities] AS [c] -WHERE ([c].[Location] = @__value_0) AND [c].[Location] IS NOT NULL"); +WHERE [c].[Location] = @__value_0"); } public override async Task Non_unicode_string_literals_in_contains_is_used_for_non_unicode_column(bool isAsync) @@ -1912,13 +1873,10 @@ public override async Task Non_unicode_string_literals_is_used_for_non_unicode_c AssertSql( @"SELECT [c].[Name], [c].[Location], [c].[Nation] FROM [Cities] AS [c] -WHERE (([c].[Location] = 'Unknown') AND [c].[Location] IS NOT NULL) AND ((( +WHERE ([c].[Location] = 'Unknown') AND (( SELECT COUNT(*) FROM [Gears] AS [g] - WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([c].[Name] = [g].[CityOfBirthName])) AND ([g].[Nickname] = N'Paduk')) = 1) AND ( - SELECT COUNT(*) - FROM [Gears] AS [g] - WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([c].[Name] = [g].[CityOfBirthName])) AND ([g].[Nickname] = N'Paduk')) IS NOT NULL)"); + WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([c].[Name] = [g].[CityOfBirthName])) AND ([g].[Nickname] = N'Paduk')) = 1)"); } public override async Task Non_unicode_string_literals_is_used_for_non_unicode_column_in_subquery(bool isAsync) @@ -1929,7 +1887,7 @@ public override async Task Non_unicode_string_literals_is_used_for_non_unicode_c @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] INNER JOIN [Cities] AS [c] ON [g].[CityOfBirthName] = [c].[Name] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Nickname] = N'Marcus') AND (([c].[Location] = 'Jacinto''s location') AND [c].[Location] IS NOT NULL))"); +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Nickname] = N'Marcus') AND ([c].[Location] = 'Jacinto''s location'))"); } public override async Task Non_unicode_string_literals_is_used_for_non_unicode_column_with_contains(bool isAsync) @@ -2154,7 +2112,7 @@ public override async Task Coalesce_operator_in_predicate_with_other_conditions( AssertSql( @"SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] -WHERE (([w].[AmmunitionType] = 1) AND [w].[AmmunitionType] IS NOT NULL) AND (COALESCE([w].[IsAutomatic], CAST(0 AS bit)) = CAST(1 AS bit))"); +WHERE ([w].[AmmunitionType] = 1) AND (COALESCE([w].[IsAutomatic], CAST(0 AS bit)) = CAST(1 AS bit))"); } public override async Task Coalesce_operator_in_projection_with_other_conditions(bool isAsync) @@ -2180,7 +2138,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE (([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL) AND ([t0].[HasSoulPatch] = CAST(1 AS bit))"); } @@ -2195,7 +2153,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE [t0].[HasSoulPatch] = CAST(1 AS bit)"); } @@ -2210,7 +2168,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE [t0].[HasSoulPatch] <> CAST(1 AS bit)"); } @@ -2225,7 +2183,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE CASE WHEN [t0].[HasSoulPatch] = CAST(1 AS bit) THEN CAST(1 AS bit) ELSE [t0].[HasSoulPatch] @@ -2243,7 +2201,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE CASE WHEN [t0].[HasSoulPatch] <> CAST(1 AS bit) THEN CAST(0 AS bit) ELSE [t0].[HasSoulPatch] @@ -2261,7 +2219,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE CASE WHEN [t0].[HasSoulPatch] = CAST(1 AS bit) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) @@ -2279,7 +2237,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE ([t0].[HasSoulPatch] = CAST(1 AS bit)) OR (CHARINDEX(N'Cole', [t].[Note]) > 0)"); } @@ -2297,7 +2255,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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)"); +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId])"); } public override async Task Optional_navigation_type_compensation_works_with_projection(bool isAsync) @@ -2311,7 +2269,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE ([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL"); } @@ -2326,7 +2284,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE ([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL"); } @@ -2341,7 +2299,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE ([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL"); } @@ -2356,7 +2314,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE ([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL ORDER BY [t].[Note]"); } @@ -2372,7 +2330,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE ([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL"); } @@ -2387,7 +2345,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE ([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL ORDER BY [t0].[SquadId]"); } @@ -2421,7 +2379,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) + ) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE (([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL) AND ([t0].[HasSoulPatch] <> CAST(1 AS bit))) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END"); @@ -2438,7 +2396,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE (([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL) AND ([t0].[HasSoulPatch] <> CAST(1 AS bit))"); } @@ -2453,7 +2411,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) WHERE (([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL) AND [t0].[SquadId] IN ( SELECT [g0].[SquadId] FROM [Gears] AS [g0] @@ -2596,7 +2554,7 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 ([g0].[Nickname] <> N'Dom') -) AS [t] ON (([g].[Nickname] = [t].[LeaderNickname]) AND [t].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t].[LeaderSquadId]) +) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); } @@ -2674,10 +2632,7 @@ public override async Task Join_predicate_condition_equals_condition(bool isAsyn AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -INNER JOIN [Weapons] AS [w] ON CAST(1 AS bit) = CASE - WHEN [w].[SynergyWithId] IS NOT NULL THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END +INNER JOIN [Weapons] AS [w] ON [w].[SynergyWithId] IS NOT NULL WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); } @@ -2710,10 +2665,7 @@ public override async Task Left_join_predicate_condition_equals_condition(bool i AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -LEFT JOIN [Weapons] AS [w] ON CAST(1 AS bit) = CASE - WHEN [w].[SynergyWithId] IS NOT NULL THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END +LEFT JOIN [Weapons] AS [w] ON [w].[SynergyWithId] IS NOT NULL WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); } @@ -2724,7 +2676,7 @@ public override async Task Where_datetimeoffset_now(bool isAsync) AssertSql( @"SELECT [m].[Id], [m].[CodeName], [m].[Rating], [m].[Timeline] FROM [Missions] AS [m] -WHERE [m].[Timeline] <> SYSDATETIMEOFFSET()"); +WHERE ([m].[Timeline] <> SYSDATETIMEOFFSET()) OR SYSDATETIMEOFFSET() IS NULL"); } public override async Task Where_datetimeoffset_utcnow(bool isAsync) @@ -2734,7 +2686,7 @@ public override async Task Where_datetimeoffset_utcnow(bool isAsync) AssertSql( @"SELECT [m].[Id], [m].[CodeName], [m].[Rating], [m].[Timeline] FROM [Missions] AS [m] -WHERE [m].[Timeline] <> CAST(SYSUTCDATETIME() AS datetimeoffset)"); +WHERE ([m].[Timeline] <> CAST(SYSUTCDATETIME() AS datetimeoffset)) OR SYSUTCDATETIME() IS NULL"); } public override async Task Where_datetimeoffset_date_component(bool isAsync) @@ -2930,7 +2882,7 @@ public override async Task Distinct_with_optional_navigation_is_translated_to_sq AssertSql( @"SELECT DISTINCT [g].[HasSoulPatch] FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([t].[Note] <> N'Foo') OR [t].[Note] IS NULL)"); } @@ -2941,7 +2893,7 @@ public override async Task Sum_with_optional_navigation_is_translated_to_sql(boo AssertSql( @"SELECT SUM([g].[SquadId]) FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([t].[Note] <> N'Foo') OR [t].[Note] IS NULL)"); } @@ -2952,7 +2904,7 @@ public override async Task Count_with_optional_navigation_is_translated_to_sql(b AssertSql( @"SELECT COUNT(*) FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([t].[Note] <> N'Foo') OR [t].[Note] IS NULL)"); } @@ -2992,7 +2944,7 @@ LEFT JOIN ( FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ) AS [t] ON [s].[Id] = [t].[SquadId] -WHERE ([s].[Name] = N'Kilo') AND [s].[Name] IS NOT NULL"); +WHERE [s].[Name] = N'Kilo'"); } public override async Task Any_with_optional_navigation_as_subquery_predicate_is_translated_to_sql(bool isAsync) @@ -3005,8 +2957,8 @@ FROM [Squads] AS [s] WHERE NOT (EXISTS ( SELECT 1 FROM [Gears] AS [g] - LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) - WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([s].[Id] = [g].[SquadId])) AND (([t].[Note] = N'Dom''s Tag') AND [t].[Note] IS NOT NULL)))"); + LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) + WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([s].[Id] = [g].[SquadId])) AND ([t].[Note] = N'Dom''s Tag')))"); } public override async Task All_with_optional_navigation_is_translated_to_sql(bool isAsync) @@ -3018,7 +2970,7 @@ public override async Task All_with_optional_navigation_is_translated_to_sql(boo WHEN NOT EXISTS ( SELECT 1 FROM [Gears] AS [g] - LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) + LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([t].[Note] = N'Foo') AND [t].[Note] IS NOT NULL)) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END"); @@ -3089,7 +3041,7 @@ public override async Task Where_is_properly_lifted_from_subquery_created_by_inc AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[Note] FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[FullName] <> N'Augustus Cole')) AND ([g].[HasSoulPatch] <> CAST(1 AS bit)) ORDER BY [g].[FullName]"); } @@ -3170,7 +3122,7 @@ FROM [Gears] AS [g] WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND EXISTS ( SELECT 1 FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL)) AND ([g].[HasSoulPatch] <> CAST(1 AS bit)) + WHERE [g].[FullName] = [w].[OwnerFullName])) AND ([g].[HasSoulPatch] <> CAST(1 AS bit)) ORDER BY [g].[Nickname]"); } @@ -3454,7 +3406,7 @@ public override async Task Collection_navigation_access_on_derived_entity_using_ @"SELECT [f].[Name], ( SELECT COUNT(*) FROM [LocustLeaders] AS [l] - WHERE [l].[Discriminator] IN (N'LocustLeader', N'LocustCommander') AND (([f].[Id] = [l].[LocustHordeId]) AND [l].[LocustHordeId] IS NOT NULL)) AS [LeadersCount] + WHERE [l].[Discriminator] IN (N'LocustLeader', N'LocustCommander') AND ([f].[Id] = [l].[LocustHordeId])) AS [LeadersCount] FROM [Factions] AS [f] WHERE ([f].[Discriminator] = N'LocustHorde') AND ([f].[Discriminator] = N'LocustHorde') ORDER BY [f].[Name]"); @@ -3654,8 +3606,8 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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].[DefeatedByNickname] = [t1].[Nickname]) AND [t0].[DefeatedByNickname] IS NOT NULL) AND (([t0].[DefeatedBySquadId] = [t1].[SquadId]) AND [t0].[DefeatedBySquadId] IS NOT NULL) -WHERE (([f].[Discriminator] = N'LocustHorde') AND (([f].[Discriminator] = N'LocustHorde') AND ([t].[HasSoulPatch] = CAST(1 AS bit)))) AND ((([t1].[Nickname] = [t].[Nickname]) AND [t1].[Nickname] IS NOT NULL) AND (([t1].[SquadId] = [t].[SquadId]) AND [t1].[SquadId] IS NOT NULL))"); +) AS [t1] ON ([t0].[DefeatedByNickname] = [t1].[Nickname]) AND ([t0].[DefeatedBySquadId] = [t1].[SquadId]) +WHERE (([f].[Discriminator] = N'LocustHorde') AND (([f].[Discriminator] = N'LocustHorde') AND ([t].[HasSoulPatch] = CAST(1 AS bit)))) AND (([t1].[Nickname] = [t].[Nickname]) AND ([t1].[SquadId] = [t].[SquadId]))"); } public override async Task Comparing_entities_using_Equals_inheritance(bool isAsync) @@ -3696,11 +3648,11 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) -WHERE (([t0].[Discriminator] = N'Officer') AND [t0].[Discriminator] IS NOT NULL) AND (( +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) +WHERE ([t0].[Discriminator] = N'Officer') AND (( SELECT COUNT(*) FROM [Gears] AS [g0] - WHERE ([g0].[Discriminator] IN (N'Gear', N'Officer') AND ([t0].[Nickname] IS NOT NULL AND ((([t0].[Nickname] = [g0].[LeaderNickname]) AND [g0].[LeaderNickname] IS NOT 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].[SquadId] = [g0].[LeaderSquadId])))) AND ([g0].[Nickname] = N'Dom')) > 0)"); } public override async Task Select_null_conditional_with_inheritance(bool isAsync) @@ -3771,12 +3723,12 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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].[DefeatedByNickname] = [t0].[Nickname]) AND [t].[DefeatedByNickname] IS NOT NULL) AND (([t].[DefeatedBySquadId] = [t0].[SquadId]) AND [t].[DefeatedBySquadId] IS NOT NULL) +) AS [t0] ON ([t].[DefeatedByNickname] = [t0].[Nickname]) AND ([t].[DefeatedBySquadId] = [t0].[SquadId]) LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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) +) AS [t1] ON (([t0].[Nickname] = [t1].[LeaderNickname]) OR ([t0].[Nickname] IS NULL AND [t1].[LeaderNickname] IS NULL)) AND ([t0].[SquadId] = [t1].[LeaderSquadId]) WHERE ([f].[Discriminator] = N'LocustHorde') AND ([f].[Discriminator] = N'LocustHorde') ORDER BY [f].[Id], [t1].[Nickname], [t1].[SquadId]"); } @@ -3797,12 +3749,12 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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].[DefeatedByNickname] = [t0].[Nickname]) AND [t].[DefeatedByNickname] IS NOT NULL) AND (([t].[DefeatedBySquadId] = [t0].[SquadId]) AND [t].[DefeatedBySquadId] IS NOT NULL) +) AS [t0] ON ([t].[DefeatedByNickname] = [t0].[Nickname]) AND ([t].[DefeatedBySquadId] = [t0].[SquadId]) LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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) +) AS [t1] ON (([t0].[Nickname] = [t1].[LeaderNickname]) OR ([t0].[Nickname] IS NULL AND [t1].[LeaderNickname] IS NULL)) AND ([t0].[SquadId] = [t1].[LeaderSquadId]) WHERE ([f].[Discriminator] = N'LocustHorde') AND ([f].[Discriminator] = N'LocustHorde') ORDER BY [f].[Id], [t1].[Nickname], [t1].[SquadId]"); } @@ -3818,7 +3770,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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 [t] ON (([l].[DefeatedByNickname] = [t].[Nickname]) AND [l].[DefeatedByNickname] IS NOT NULL) AND (([l].[DefeatedBySquadId] = [t].[SquadId]) AND [l].[DefeatedBySquadId] IS NOT NULL) +) AS [t] ON ([l].[DefeatedByNickname] = [t].[Nickname]) AND ([l].[DefeatedBySquadId] = [t].[SquadId]) WHERE [l].[Discriminator] IN (N'LocustLeader', N'LocustCommander')"); } @@ -3833,7 +3785,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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 [t] ON (([l].[DefeatedByNickname] = [t].[Nickname]) AND [l].[DefeatedByNickname] IS NOT NULL) AND (([l].[DefeatedBySquadId] = [t].[SquadId]) AND [l].[DefeatedBySquadId] IS NOT NULL) +) AS [t] ON ([l].[DefeatedByNickname] = [t].[Nickname]) AND ([l].[DefeatedBySquadId] = [t].[SquadId]) LEFT JOIN [Squads] AS [s] ON [t].[SquadId] = [s].[Id] WHERE [l].[Discriminator] IN (N'LocustLeader', N'LocustCommander')"); } @@ -3849,13 +3801,13 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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 [t] ON (([l].[DefeatedByNickname] = [t].[Nickname]) AND [l].[DefeatedByNickname] IS NOT NULL) AND (([l].[DefeatedBySquadId] = [t].[SquadId]) AND [l].[DefeatedBySquadId] IS NOT NULL) +) AS [t] ON ([l].[DefeatedByNickname] = [t].[Nickname]) AND ([l].[DefeatedBySquadId] = [t].[SquadId]) 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] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') -) AS [t0] ON ((([t].[Nickname] = [t0].[LeaderNickname]) AND ([t].[Nickname] IS NOT NULL AND [t0].[LeaderNickname] IS NOT NULL)) OR ([t].[Nickname] IS NULL AND [t0].[LeaderNickname] IS NULL)) AND (([t].[SquadId] = [t0].[LeaderSquadId]) AND [t].[SquadId] IS NOT NULL) +) AS [t0] ON (([t].[Nickname] = [t0].[LeaderNickname]) OR ([t].[Nickname] IS NULL AND [t0].[LeaderNickname] IS NULL)) AND ([t].[SquadId] = [t0].[LeaderSquadId]) WHERE [l].[Discriminator] IN (N'LocustLeader', N'LocustCommander') ORDER BY [l].[Name], [t0].[Nickname], [t0].[SquadId], [t0].[Name]"); } @@ -3871,7 +3823,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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 [t] ON (([l].[DefeatedByNickname] = [t].[Nickname]) AND [l].[DefeatedByNickname] IS NOT NULL) AND (([l].[DefeatedBySquadId] = [t].[SquadId]) AND [l].[DefeatedBySquadId] IS NOT NULL) +) AS [t] ON ([l].[DefeatedByNickname] = [t].[Nickname]) AND ([l].[DefeatedBySquadId] = [t].[SquadId]) WHERE [l].[Discriminator] IN (N'LocustLeader', N'LocustCommander')"); } @@ -3886,7 +3838,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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 [t] ON (([l].[DefeatedByNickname] = [t].[Nickname]) AND [l].[DefeatedByNickname] IS NOT NULL) AND (([l].[DefeatedBySquadId] = [t].[SquadId]) AND [l].[DefeatedBySquadId] IS NOT NULL) +) AS [t] ON ([l].[DefeatedByNickname] = [t].[Nickname]) AND ([l].[DefeatedBySquadId] = [t].[SquadId]) WHERE [l].[Discriminator] IN (N'LocustLeader', N'LocustCommander')"); } @@ -3901,7 +3853,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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 [t] ON (([l].[DefeatedByNickname] = [t].[Nickname]) AND [l].[DefeatedByNickname] IS NOT NULL) AND (([l].[DefeatedBySquadId] = [t].[SquadId]) AND [l].[DefeatedBySquadId] IS NOT NULL) +) AS [t] ON ([l].[DefeatedByNickname] = [t].[Nickname]) AND ([l].[DefeatedBySquadId] = [t].[SquadId]) WHERE [l].[Discriminator] IN (N'LocustLeader', N'LocustCommander')"); } @@ -3916,7 +3868,7 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t] ON (([g].[Nickname] = [t].[LeaderNickname]) AND [t].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t].[LeaderSquadId]) +) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); } @@ -3932,7 +3884,7 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t] ON (([g].[Nickname] = [t].[LeaderNickname]) AND [t].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t].[LeaderSquadId]) +) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); } @@ -3948,7 +3900,7 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t] ON (([g].[Nickname] = [t].[LeaderNickname]) AND [t].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t].[LeaderSquadId]) +) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); } @@ -3960,7 +3912,7 @@ public override async Task Include_base_navigation_on_derived_entity(bool isAsyn AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[Note], [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) LEFT JOIN [Weapons] AS [w] ON [g].[FullName] = [w].[OwnerFullName] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [w].[Id]"); @@ -3977,7 +3929,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN [Weapons] AS [w] ON [t0].[FullName] = [w].[OwnerFullName] ORDER BY [t].[Id], [w].[Id]"); } @@ -3998,12 +3950,12 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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].[DefeatedByNickname] = [t0].[Nickname]) AND [t].[DefeatedByNickname] IS NOT NULL) AND (([t].[DefeatedBySquadId] = [t0].[SquadId]) AND [t].[DefeatedBySquadId] IS NOT NULL) +) AS [t0] ON ([t].[DefeatedByNickname] = [t0].[Nickname]) AND ([t].[DefeatedBySquadId] = [t0].[SquadId]) LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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) +) AS [t1] ON (([t0].[Nickname] = [t1].[LeaderNickname]) OR ([t0].[Nickname] IS NULL AND [t1].[LeaderNickname] IS NULL)) AND ([t0].[SquadId] = [t1].[LeaderSquadId]) WHERE [f].[Discriminator] = N'LocustHorde' ORDER BY [f].[Id], [t1].[Nickname], [t1].[SquadId]"); } @@ -4022,9 +3974,9 @@ LEFT JOIN ( SELECT [g1].[Nickname], [g1].[SquadId], [g1].[AssignedCityName], [g1].[CityOfBirthName], [g1].[Discriminator], [g1].[FullName], [g1].[HasSoulPatch], [g1].[LeaderNickname], [g1].[LeaderSquadId], [g1].[Rank] FROM [Gears] AS [g1] WHERE [g1].[Discriminator] IN (N'Gear', N'Officer') - ) AS [t] ON (([g0].[Nickname] = [t].[LeaderNickname]) AND [t].[LeaderNickname] IS NOT NULL) AND ([g0].[SquadId] = [t].[LeaderSquadId]) + ) AS [t] ON ([g0].[Nickname] = [t].[LeaderNickname]) AND ([g0].[SquadId] = [t].[LeaderSquadId]) WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') -) AS [t0] ON (([g].[Nickname] = [t0].[LeaderNickname]) AND [t0].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t0].[LeaderSquadId]) +) AS [t0] ON ([g].[Nickname] = [t0].[LeaderNickname]) AND ([g].[SquadId] = [t0].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [t0].[Nickname], [t0].[SquadId], [t0].[Nickname0], [t0].[SquadId0]"); } @@ -4043,7 +3995,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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 [t] ON (([l].[DefeatedByNickname] = [t].[Nickname]) AND [l].[DefeatedByNickname] IS NOT NULL) AND (([l].[DefeatedBySquadId] = [t].[SquadId]) AND [l].[DefeatedBySquadId] IS NOT NULL) + ) AS [t] ON ([l].[DefeatedByNickname] = [t].[Nickname]) AND ([l].[DefeatedBySquadId] = [t].[SquadId]) WHERE [l].[Discriminator] IN (N'LocustLeader', N'LocustCommander') ) AS [t0] ON [f].[Id] = [t0].[LocustHordeId] WHERE [f].[Discriminator] = N'LocustHorde' @@ -4066,12 +4018,12 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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].[DefeatedByNickname] = [t0].[Nickname]) AND [t].[DefeatedByNickname] IS NOT NULL) AND (([t].[DefeatedBySquadId] = [t0].[SquadId]) AND [t].[DefeatedBySquadId] IS NOT NULL) +) AS [t0] ON ([t].[DefeatedByNickname] = [t0].[Nickname]) AND ([t].[DefeatedBySquadId] = [t0].[SquadId]) LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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) +) AS [t1] ON (([t0].[Nickname] = [t1].[LeaderNickname]) OR ([t0].[Nickname] IS NULL AND [t1].[LeaderNickname] IS NULL)) AND ([t0].[SquadId] = [t1].[LeaderSquadId]) WHERE [f].[Discriminator] = N'LocustHorde' ORDER BY [f].[Id], [t1].[Nickname], [t1].[SquadId]"); } @@ -4089,7 +4041,7 @@ FROM [Gears] AS [g0] INNER JOIN [Squads] AS [s] ON [g0].[SquadId] = [s].[Id] LEFT JOIN [SquadMissions] AS [s0] ON [s].[Id] = [s0].[SquadId] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') -) AS [t] ON (([g].[Nickname] = [t].[LeaderNickname]) AND [t].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t].[LeaderSquadId]) +) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId], [t].[Id], [t].[SquadId0], [t].[MissionId]"); } @@ -4108,7 +4060,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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)"); +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId])"); } public override async Task Enum_ToString_is_client_eval(bool isAsync) @@ -4233,7 +4185,7 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[FullName], [g0].[SquadId], [g0].[LeaderNickname], [g0].[LeaderSquadId] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') AND ([g0].[HasSoulPatch] <> CAST(1 AS bit)) -) AS [t] ON (([g].[Nickname] = [t].[LeaderNickname]) AND [t].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t].[LeaderSquadId]) +) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer')) AND ([g].[Nickname] <> N'Foo') ORDER BY [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); } @@ -4398,7 +4350,7 @@ FROM [Weapons] AS [w] WHERE ([w].[Name] <> N'Bar') OR [w].[Name] IS NULL ) AS [t] ON [g0].[FullName] = [t].[OwnerFullName] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') AND ([g0].[FullName] <> N'Foo') -) AS [t0] ON (([g].[Nickname] = [t0].[LeaderNickname]) AND [t0].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t0].[LeaderSquadId]) +) AS [t0] ON ([g].[Nickname] = [t0].[LeaderNickname]) AND ([g].[SquadId] = [t0].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY [g].[HasSoulPatch] DESC, [g].[Nickname], [g].[SquadId], [t0].[Rank], [t0].[Nickname], [t0].[SquadId], [t0].[IsAutomatic], [t0].[Id]"); } @@ -4461,7 +4413,7 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[Rank], [g0].[SquadId], [g0].[FullName], [g0].[LeaderNickname], [g0].[LeaderSquadId] FROM [Gears] AS [g0] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') -) AS [t0] ON (([g].[Nickname] = [t0].[LeaderNickname]) AND [t0].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t0].[LeaderSquadId]) +) AS [t0] ON ([g].[Nickname] = [t0].[LeaderNickname]) AND ([g].[SquadId] = [t0].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[FullName], [t0].[Nickname], [t0].[SquadId]"); } @@ -4473,11 +4425,11 @@ public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_ AssertSql( @"SELECT [g].[FullName] FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer')) AND EXISTS ( SELECT 1 FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') AND ((([g].[Nickname] = [g0].[LeaderNickname]) AND [g0].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [g0].[LeaderSquadId]))) + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId]))) ORDER BY [g].[HasSoulPatch] DESC, [t].[Note]"); } @@ -4488,12 +4440,12 @@ public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_ AssertSql( @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t2].[Id], [t2].[AmmunitionType], [t2].[IsAutomatic], [t2].[Name], [t2].[OwnerFullName], [t2].[SynergyWithId] FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t0] ON (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN ( SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], [t1].[Nickname] FROM [Weapons] AS [w] @@ -4506,7 +4458,7 @@ WHERE [g1].[Discriminator] IN (N'Gear', N'Officer') WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer')) AND EXISTS ( SELECT 1 FROM [Gears] AS [g2] - WHERE [g2].[Discriminator] IN (N'Gear', N'Officer') AND ((([g].[Nickname] = [g2].[LeaderNickname]) AND [g2].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [g2].[LeaderSquadId]))) + WHERE [g2].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Nickname] = [g2].[LeaderNickname]) AND ([g].[SquadId] = [g2].[LeaderSquadId]))) ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t2].[IsAutomatic], [t2].[Nickname] DESC, [t2].[Id]"); } @@ -4518,12 +4470,12 @@ public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_ AssertSql( @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t2].[Id], [t2].[AmmunitionType], [t2].[IsAutomatic], [t2].[Name], [t2].[OwnerFullName], [t2].[SynergyWithId] FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t0] ON (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN ( SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], [t1].[Nickname] FROM [Weapons] AS [w] @@ -4536,7 +4488,7 @@ WHERE [g1].[Discriminator] IN (N'Gear', N'Officer') WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer')) AND EXISTS ( SELECT 1 FROM [Gears] AS [g2] - WHERE [g2].[Discriminator] IN (N'Gear', N'Officer') AND ((([g].[Nickname] = [g2].[LeaderNickname]) AND [g2].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [g2].[LeaderSquadId]))) + WHERE [g2].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Nickname] = [g2].[LeaderNickname]) AND ([g].[SquadId] = [g2].[LeaderSquadId]))) ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t2].[IsAutomatic], [t2].[Nickname] DESC, [t2].[Id]"); } @@ -4548,17 +4500,17 @@ public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_ AssertSql( @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t2].[Id], [t2].[AmmunitionType], [t2].[IsAutomatic], [t2].[Name], [t2].[OwnerFullName], [t2].[SynergyWithId] FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t0] ON (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN ( SELECT [w0].[Id], [w0].[AmmunitionType], [w0].[IsAutomatic], [w0].[Name], [w0].[OwnerFullName], [w0].[SynergyWithId], ( SELECT COUNT(*) FROM [Weapons] AS [w] - WHERE [t1].[FullName] IS NOT NULL AND (([t1].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL)) AS [c] + WHERE [t1].[FullName] IS NOT NULL AND ([t1].[FullName] = [w].[OwnerFullName])) AS [c] FROM [Weapons] AS [w0] LEFT JOIN ( SELECT [g1].[Nickname], [g1].[SquadId], [g1].[AssignedCityName], [g1].[CityOfBirthName], [g1].[Discriminator], [g1].[FullName], [g1].[HasSoulPatch], [g1].[LeaderNickname], [g1].[LeaderSquadId], [g1].[Rank] @@ -4569,7 +4521,7 @@ WHERE [g1].[Discriminator] IN (N'Gear', N'Officer') WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer')) AND EXISTS ( SELECT 1 FROM [Gears] AS [g2] - WHERE [g2].[Discriminator] IN (N'Gear', N'Officer') AND ((([g].[Nickname] = [g2].[LeaderNickname]) AND [g2].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [g2].[LeaderSquadId]))) + WHERE [g2].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Nickname] = [g2].[LeaderNickname]) AND ([g].[SquadId] = [g2].[LeaderSquadId]))) ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t2].[Id] DESC, [t2].[c]"); } @@ -4580,12 +4532,12 @@ public override async Task Correlated_collections_multiple_nested_complex_collec AssertSql( @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t4].[FullName], [t4].[Nickname], [t4].[SquadId], [t4].[Id], [t4].[Name], [t4].[IsAutomatic], [t4].[Id0], [t4].[Nickname0], [t4].[HasSoulPatch], [t4].[SquadId0], [t6].[Id], [t6].[AmmunitionType], [t6].[IsAutomatic], [t6].[Name], [t6].[OwnerFullName], [t6].[SynergyWithId] FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t0] ON (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN ( SELECT [g1].[FullName], [g1].[Nickname], [g1].[SquadId], [t3].[Id], [t3].[Name], [t3].[IsAutomatic], [t3].[Id0], [t3].[Nickname] AS [Nickname0], [t3].[HasSoulPatch], [t3].[SquadId] AS [SquadId0], [g1].[Rank], [t3].[IsAutomatic0], [g1].[LeaderNickname], [g1].[LeaderSquadId] FROM [Gears] AS [g1] @@ -4607,7 +4559,7 @@ WHERE [g3].[Discriminator] IN (N'Gear', N'Officer') WHERE ([w].[Name] <> N'Bar') OR [w].[Name] IS NULL ) AS [t3] ON [g1].[FullName] = [t3].[OwnerFullName] WHERE [g1].[Discriminator] IN (N'Gear', N'Officer') AND ([g1].[FullName] <> N'Foo') -) AS [t4] ON (([g].[Nickname] = [t4].[LeaderNickname]) AND [t4].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t4].[LeaderSquadId]) +) AS [t4] ON ([g].[Nickname] = [t4].[LeaderNickname]) AND ([g].[SquadId] = [t4].[LeaderSquadId]) LEFT JOIN ( SELECT [w1].[Id], [w1].[AmmunitionType], [w1].[IsAutomatic], [w1].[Name], [w1].[OwnerFullName], [w1].[SynergyWithId], [t5].[Nickname] FROM [Weapons] AS [w1] @@ -4620,7 +4572,7 @@ WHERE [g4].[Discriminator] IN (N'Gear', N'Officer') WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer')) AND EXISTS ( SELECT 1 FROM [Gears] AS [g5] - WHERE [g5].[Discriminator] IN (N'Gear', N'Officer') AND ((([g].[Nickname] = [g5].[LeaderNickname]) AND [g5].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [g5].[LeaderSquadId]))) + WHERE [g5].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Nickname] = [g5].[LeaderNickname]) AND ([g].[SquadId] = [g5].[LeaderSquadId]))) ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t4].[Rank], [t4].[Nickname], [t4].[SquadId], [t4].[IsAutomatic0], [t4].[Id], [t4].[Id0], [t4].[Nickname0], [t4].[SquadId0], [t6].[IsAutomatic], [t6].[Nickname] DESC, [t6].[Id]"); } @@ -4634,7 +4586,7 @@ FROM [Gears] AS [g] OUTER APPLY ( SELECT [g0].[FullName], [g].[FullName] AS [FullName0], [g0].[Nickname], [g0].[SquadId] FROM [Gears] AS [g0] - WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') AND ((([g].[Nickname] = [g0].[LeaderNickname]) AND [g0].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [g0].[LeaderSquadId])) + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId])) ) AS [t] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); @@ -4650,7 +4602,7 @@ FROM [Gears] AS [g] OUTER APPLY ( SELECT [g0].[FullName], [g0].[Nickname], [g0].[SquadId] FROM [Gears] AS [g0] - WHERE ([g0].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[FullName] <> N'Foo')) AND ((([g].[Nickname] = [g0].[LeaderNickname]) AND [g0].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [g0].[LeaderSquadId])) + WHERE ([g0].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[FullName] <> N'Foo')) AND (([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId])) ) AS [t] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); @@ -4669,10 +4621,10 @@ FROM [Gears] AS [g0] OUTER APPLY ( SELECT [w].[Name], [g0].[Nickname], [w].[Id] FROM [Weapons] AS [w] - WHERE (([w].[Name] <> N'Bar') OR [w].[Name] IS NULL) AND (([g0].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) + WHERE (([w].[Name] <> N'Bar') OR [w].[Name] IS NULL) AND ([g0].[FullName] = [w].[OwnerFullName]) ) AS [t] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') AND ([g0].[FullName] <> N'Foo') -) AS [t0] ON (([g].[Nickname] = [t0].[LeaderNickname]) AND [t0].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t0].[LeaderSquadId]) +) AS [t0] ON ([g].[Nickname] = [t0].[LeaderNickname]) AND ([g].[SquadId] = [t0].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [t0].[Nickname], [t0].[SquadId], [t0].[Id]"); } @@ -4692,7 +4644,7 @@ LEFT JOIN ( FROM [Weapons] AS [w] WHERE ([w].[Name] <> N'Bar') OR [w].[Name] IS NULL ) AS [t] ON [g0].[FullName] = [t].[OwnerFullName] - WHERE ([g0].[Discriminator] IN (N'Gear', N'Officer') AND ([g0].[FullName] <> N'Foo')) AND ((([g].[Nickname] = [g0].[LeaderNickname]) AND [g0].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [g0].[LeaderSquadId])) + WHERE ([g0].[Discriminator] IN (N'Gear', N'Officer') AND ([g0].[FullName] <> N'Foo')) AND (([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId])) ) AS [t0] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [t0].[Nickname], [t0].[SquadId], [t0].[Id]"); @@ -4848,7 +4800,7 @@ LEFT JOIN ( SELECT [g0].[FullName], [g0].[Nickname], [g0].[SquadId], [g0].[LeaderNickname], [g0].[LeaderSquadId] 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) +) AS [t1] ON (([t0].[Nickname] = [t1].[LeaderNickname]) OR ([t0].[Nickname] IS NULL AND [t1].[LeaderNickname] IS NULL)) AND ([t0].[SquadId] = [t1].[LeaderSquadId]) ORDER BY [t].[Id], [t1].[Nickname], [t1].[SquadId]"); } @@ -4956,7 +4908,7 @@ WHERE [g2].[Discriminator] IN (N'Gear', N'Officer') ) AS [t0] ON [s].[Id] = [t0].[SquadId] ) AS [t1] ON [g0].[FullName] = [t1].[OwnerFullName] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') -) AS [t2] ON (([g].[Nickname] = [t2].[LeaderNickname]) AND [t2].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t2].[LeaderSquadId]) +) AS [t2] ON ([g].[Nickname] = [t2].[LeaderNickname]) AND ([g].[SquadId] = [t2].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY [g].[Nickname], [g].[SquadId], [t2].[Nickname], [t2].[SquadId], [t2].[Id], [t2].[Nickname0], [t2].[SquadId0]"); } @@ -5013,7 +4965,7 @@ WHERE [g2].[Discriminator] IN (N'Gear', N'Officer') ) AS [t0] ON [s].[Id] = [t0].[SquadId] ) AS [t1] ON [g0].[FullName] = [t1].[OwnerFullName] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') -) AS [t2] ON (([g].[Nickname] = [t2].[LeaderNickname]) AND [t2].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t2].[LeaderSquadId]) +) AS [t2] ON ([g].[Nickname] = [t2].[LeaderNickname]) AND ([g].[SquadId] = [t2].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY [g].[HasSoulPatch], [g].[LeaderNickname], [g].[FullName], [g].[Nickname], [g].[SquadId], [t2].[FullName], [t2].[HasSoulPatch0] DESC, [t2].[Nickname], [t2].[SquadId], [t2].[IsAutomatic], [t2].[Name] DESC, [t2].[Id], [t2].[Nickname0], [t2].[SquadId0]"); } @@ -5171,7 +5123,7 @@ FROM [LocustLeaders] AS [l] INNER JOIN ( SELECT [f].[Id], [f].[CapitalName], [f].[Discriminator], [f].[Name], [f].[CommanderName], [f].[Eradicated] FROM [Factions] AS [f] - WHERE (([f].[Discriminator] = N'LocustHorde') AND ([f].[Discriminator] = N'LocustHorde')) AND (([f].[Name] = N'Swarm') AND [f].[Name] IS NOT NULL) + WHERE (([f].[Discriminator] = N'LocustHorde') AND ([f].[Discriminator] = N'LocustHorde')) AND ([f].[Name] = N'Swarm') ) AS [t] ON [l].[Name] = [t].[CommanderName] WHERE [l].[Discriminator] IN (N'LocustLeader', N'LocustCommander') AND (([t].[Eradicated] <> CAST(1 AS bit)) OR [t].[Eradicated] IS NULL)"); } @@ -5186,7 +5138,7 @@ FROM [LocustLeaders] AS [l] LEFT JOIN ( SELECT [f].[Id], [f].[CapitalName], [f].[Discriminator], [f].[Name], [f].[CommanderName], [f].[Eradicated] FROM [Factions] AS [f] - WHERE (([f].[Discriminator] = N'LocustHorde') AND ([f].[Discriminator] = N'LocustHorde')) AND (([f].[Name] = N'Swarm') AND [f].[Name] IS NOT NULL) + WHERE (([f].[Discriminator] = N'LocustHorde') AND ([f].[Discriminator] = N'LocustHorde')) AND ([f].[Name] = N'Swarm') ) AS [t] ON [l].[Name] = [t].[CommanderName] WHERE [l].[Discriminator] IN (N'LocustLeader', N'LocustCommander') AND (([t].[Eradicated] <> CAST(1 AS bit)) OR [t].[Eradicated] IS NULL)"); } @@ -5213,8 +5165,8 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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 [t] ON (([l].[DefeatedByNickname] = [t].[Nickname]) AND [l].[DefeatedByNickname] IS NOT NULL) AND (([l].[DefeatedBySquadId] = [t].[SquadId]) AND [l].[DefeatedBySquadId] IS NOT NULL) - LEFT JOIN [Tags] AS [t0] ON ((([t].[Nickname] = [t0].[GearNickName]) AND ([t].[Nickname] IS NOT NULL AND [t0].[GearNickName] IS NOT NULL)) OR ([t].[Nickname] IS NULL AND [t0].[GearNickName] IS NULL)) AND ((([t].[SquadId] = [t0].[GearSquadId]) AND ([t].[SquadId] IS NOT NULL AND [t0].[GearSquadId] IS NOT NULL)) OR ([t].[SquadId] IS NULL AND [t0].[GearSquadId] IS NULL)) + ) AS [t] ON ([l].[DefeatedByNickname] = [t].[Nickname]) AND ([l].[DefeatedBySquadId] = [t].[SquadId]) + LEFT JOIN [Tags] AS [t0] ON (([t].[Nickname] = [t0].[GearNickName]) OR ([t].[Nickname] IS NULL AND [t0].[GearNickName] IS NULL)) AND (([t].[SquadId] = [t0].[GearSquadId]) OR ([t].[SquadId] IS NULL AND [t0].[GearSquadId] IS NULL)) WHERE [l].[Discriminator] IN (N'LocustLeader', N'LocustCommander') ORDER BY [t0].[Note] ) AS [t1] @@ -5222,7 +5174,7 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t2] ON (([t1].[DefeatedByNickname] = [t2].[Nickname]) AND [t1].[DefeatedByNickname] IS NOT NULL) AND (([t1].[DefeatedBySquadId] = [t2].[SquadId]) AND [t1].[DefeatedBySquadId] IS NOT NULL) +) AS [t2] ON ([t1].[DefeatedByNickname] = [t2].[Nickname]) AND ([t1].[DefeatedBySquadId] = [t2].[SquadId]) LEFT JOIN [Weapons] AS [w] ON [t2].[FullName] = [w].[OwnerFullName] ORDER BY [t1].[Note], [t1].[Name], [w].[Id]"); } @@ -5368,7 +5320,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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)"); +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId])"); } public override async Task Order_by_entity_qsre(bool isAsync) @@ -5506,9 +5458,9 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t0] ON (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) - WHERE (([t].[Note] = N'Cole''s Tag') AND [t].[Note] IS NOT NULL) OR (([t].[Note] = N'Dom''s Tag') AND [t].[Note] IS NOT NULL) -) AS [t1] ON (([g].[Nickname] = [t1].[Nickname]) AND [t1].[Nickname] IS NOT NULL) AND (([g].[SquadId] = [t1].[SquadId]) AND [t1].[SquadId] IS NOT NULL) + ) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) + WHERE ([t].[Note] = N'Cole''s Tag') OR ([t].[Note] = N'Dom''s Tag') +) AS [t1] ON ([g].[Nickname] = [t1].[Nickname]) AND ([g].[SquadId] = [t1].[SquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); } @@ -5681,7 +5633,7 @@ SELECT TOP(1) [g].[SquadId] FROM [Gears] AS [g] WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([s].[Id] = [g].[SquadId])) AND ([g].[HasSoulPatch] = CAST(1 AS bit))) AS [SquadId] FROM [Squads] AS [s] -WHERE ([s].[Name] = N'Kilo') AND [s].[Name] IS NOT NULL"); +WHERE [s].[Name] = N'Kilo'"); } public override async Task Project_one_value_type_converted_to_nullable_from_empty_collection(bool isAsync) @@ -5694,7 +5646,7 @@ SELECT TOP(1) [g].[SquadId] FROM [Gears] AS [g] WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([s].[Id] = [g].[SquadId])) AND ([g].[HasSoulPatch] = CAST(1 AS bit))) AS [SquadId] FROM [Squads] AS [s] -WHERE ([s].[Name] = N'Kilo') AND [s].[Name] IS NOT NULL"); +WHERE [s].[Name] = N'Kilo'"); } public override async Task Project_one_value_type_with_client_projection_from_empty_collection(bool isAsync) @@ -5713,7 +5665,7 @@ WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] = CAS ) AS [t] WHERE [t].[row] <= 1 ) AS [t0] ON [s].[Id] = [t0].[SquadId] -WHERE ([s].[Name] = N'Kilo') AND [s].[Name] IS NOT NULL"); +WHERE [s].[Name] = N'Kilo'"); } public override async Task Filter_on_subquery_projecting_one_value_type_from_empty_collection(bool isAsync) @@ -5931,12 +5883,12 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t] ON (([g].[Nickname] = [t].[LeaderNickname]) AND [t].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t].[LeaderSquadId]) +) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY ( SELECT COUNT(*) FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL), [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); + WHERE [g].[FullName] = [w].[OwnerFullName]), [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); } public override async Task Include_collection_with_complex_OrderBy2(bool isAsync) @@ -5950,12 +5902,12 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t] ON (([g].[Nickname] = [t].[LeaderNickname]) AND [t].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t].[LeaderSquadId]) +) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY ( SELECT TOP(1) [w].[IsAutomatic] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ORDER BY [w].[Id]), [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); } @@ -5970,12 +5922,12 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [t] ON (([g].[Nickname] = [t].[LeaderNickname]) AND [t].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t].[LeaderSquadId]) +) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY ( SELECT TOP(1) [w].[IsAutomatic] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ORDER BY [w].[Id]), [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); } @@ -5990,12 +5942,12 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 ([g0].[HasSoulPatch] <> CAST(1 AS bit)) -) AS [t] ON (([g].[Nickname] = [t].[LeaderNickname]) AND [t].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t].[LeaderSquadId]) +) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY ( SELECT COUNT(*) FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL), [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); + WHERE [g].[FullName] = [w].[OwnerFullName]), [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); } public override async Task Correlated_collection_with_very_complex_order_by(bool isAsync) @@ -6009,18 +5961,15 @@ LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 ([g0].[HasSoulPatch] <> CAST(1 AS bit)) -) AS [t] ON (([g].[Nickname] = [t].[LeaderNickname]) AND [t].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t].[LeaderSquadId]) +) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Discriminator] = N'Officer') ORDER BY ( SELECT COUNT(*) FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND (([w].[IsAutomatic] = ( - SELECT TOP(1) [g1].[HasSoulPatch] - FROM [Gears] AS [g1] - WHERE [g1].[Discriminator] IN (N'Gear', N'Officer') AND ([g1].[Nickname] = N'Marcus'))) AND ( + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND ([w].[IsAutomatic] = ( SELECT TOP(1) [g1].[HasSoulPatch] FROM [Gears] AS [g1] - WHERE [g1].[Discriminator] IN (N'Gear', N'Officer') AND ([g1].[Nickname] = N'Marcus')) IS NOT NULL)), [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); + WHERE [g1].[Discriminator] IN (N'Gear', N'Officer') AND ([g1].[Nickname] = N'Marcus')))), [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); } public override async Task Cast_to_derived_type_after_OfType_works(bool isAsync) @@ -6041,7 +5990,7 @@ public override async Task Select_subquery_boolean(bool isAsync) @"SELECT ( SELECT TOP(1) [w].[IsAutomatic] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ORDER BY [w].[Id]) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); @@ -6055,7 +6004,7 @@ public override async Task Select_subquery_boolean_with_pushdown(bool isAsync) @"SELECT ( SELECT TOP(1) [w].[IsAutomatic] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ORDER BY [w].[Id]) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); @@ -6069,7 +6018,7 @@ public override async Task Select_subquery_int_with_inside_cast_and_coalesce(boo @"SELECT COALESCE(( SELECT TOP(1) [w].[Id] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ORDER BY [w].[Id]), 42) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); @@ -6083,7 +6032,7 @@ public override async Task Select_subquery_int_with_outside_cast_and_coalesce(bo @"SELECT COALESCE(( SELECT TOP(1) [w].[Id] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ORDER BY [w].[Id]), 42) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); @@ -6097,7 +6046,7 @@ public override async Task Select_subquery_int_with_pushdown_and_coalesce(bool i @"SELECT COALESCE(( SELECT TOP(1) [w].[Id] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ORDER BY [w].[Id]), 42) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); @@ -6111,11 +6060,11 @@ public override async Task Select_subquery_int_with_pushdown_and_coalesce2(bool @"SELECT COALESCE(( SELECT TOP(1) [w].[Id] FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w].[OwnerFullName] ORDER BY [w].[Id]), ( SELECT TOP(1) [w0].[Id] FROM [Weapons] AS [w0] - WHERE ([g].[FullName] = [w0].[OwnerFullName]) AND [w0].[OwnerFullName] IS NOT NULL + WHERE [g].[FullName] = [w0].[OwnerFullName] ORDER BY [w0].[Id])) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); @@ -6129,7 +6078,7 @@ public override async Task Select_subquery_boolean_empty(bool isAsync) @"SELECT ( SELECT TOP(1) [w].[IsAutomatic] FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND (([w].[Name] = N'BFG') AND [w].[Name] IS NOT NULL) + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND ([w].[Name] = N'BFG') ORDER BY [w].[Id]) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); @@ -6143,7 +6092,7 @@ public override async Task Select_subquery_boolean_empty_with_pushdown(bool isAs @"SELECT ( SELECT TOP(1) [w].[IsAutomatic] FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND (([w].[Name] = N'BFG') AND [w].[Name] IS NOT NULL) + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND ([w].[Name] = N'BFG') ORDER BY [w].[Id]) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); @@ -6157,7 +6106,7 @@ public override async Task Select_subquery_boolean_empty_with_pushdown_without_c @"SELECT ( SELECT TOP(1) [w].[IsAutomatic] FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND (([w].[Name] = N'BFG') AND [w].[Name] IS NOT NULL) + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND ([w].[Name] = N'BFG') ORDER BY [w].[Id]) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); @@ -6171,7 +6120,7 @@ public override async Task Select_subquery_boolean_empty_with_pushdown_without_c @"SELECT ( SELECT TOP(1) [w].[Id] FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND (([w].[Name] = N'BFG') AND [w].[Name] IS NOT NULL) + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND ([w].[Name] = N'BFG') ORDER BY [w].[Id]) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); @@ -6187,7 +6136,7 @@ SELECT TOP(1) [t].[IsAutomatic] FROM ( SELECT DISTINCT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND (CHARINDEX(N'Lancer', [w].[Name]) > 0) + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND (CHARINDEX(N'Lancer', [w].[Name]) > 0) ) AS [t]) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] = CAST(1 AS bit))"); @@ -6201,7 +6150,7 @@ public override async Task Select_subquery_distinct_singleordefault_boolean2(boo @"SELECT ( SELECT DISTINCT TOP(1) [w].[IsAutomatic] FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND (CHARINDEX(N'Lancer', [w].[Name]) > 0)) + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND (CHARINDEX(N'Lancer', [w].[Name]) > 0)) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] = CAST(1 AS bit))"); } @@ -6216,7 +6165,7 @@ SELECT TOP(1) [t].[IsAutomatic] FROM ( SELECT DISTINCT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND (CHARINDEX(N'Lancer', [w].[Name]) > 0) + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND (CHARINDEX(N'Lancer', [w].[Name]) > 0) ) AS [t]) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] = CAST(1 AS bit))"); @@ -6232,7 +6181,7 @@ SELECT TOP(1) [t].[IsAutomatic] FROM ( SELECT DISTINCT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND (([w].[Name] = N'BFG') AND [w].[Name] IS NOT NULL) + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND ([w].[Name] = N'BFG') ) AS [t]) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] = CAST(1 AS bit))"); @@ -6246,7 +6195,7 @@ public override async Task Select_subquery_distinct_singleordefault_boolean_empt @"SELECT ( SELECT DISTINCT TOP(1) [w].[IsAutomatic] FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND (([w].[Name] = N'BFG') AND [w].[Name] IS NOT NULL)) + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND ([w].[Name] = N'BFG')) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] = CAST(1 AS bit))"); } @@ -6261,7 +6210,7 @@ SELECT TOP(1) [t].[IsAutomatic] FROM ( SELECT DISTINCT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND (([w].[Name] = N'BFG') AND [w].[Name] IS NOT NULL) + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND ([w].[Name] = N'BFG') ) AS [t]) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] = CAST(1 AS bit))"); @@ -6589,7 +6538,7 @@ public override async Task Include_with_client_method_and_member_access_still_ap AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[Note] FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); } @@ -6618,7 +6567,7 @@ FROM [Gears] AS [g] LEFT JOIN [Weapons] AS [w] ON [g].[FullName] = [w].[OwnerFullName] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ) AS [t] ON [s].[Id] = [t].[SquadId] -WHERE ([s].[Name] = N'Delta') AND [s].[Name] IS NOT NULL +WHERE [s].[Name] = N'Delta' ORDER BY [s].[Id], [t].[Nickname], [t].[SquadId], [t].[Id]"); } @@ -6629,7 +6578,7 @@ public override async Task OrderBy_same_expression_containing_IsNull_correctly_d AssertSql( @"SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CASE - WHEN CAST(LEN([g].[Nickname]) AS int) = 5 THEN CAST(1 AS bit) + WHEN (CAST(LEN([g].[Nickname]) AS int) = 5) AND LEN([g].[Nickname]) IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END ELSE NULL @@ -6639,13 +6588,14 @@ WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ORDER BY CASE WHEN CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CASE - WHEN CAST(LEN([g].[Nickname]) AS int) = 5 THEN CAST(1 AS bit) + WHEN (CAST(LEN([g].[Nickname]) AS int) = 5) AND LEN([g].[Nickname]) IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END ELSE NULL END IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END"); + } public override async Task GetValueOrDefault_in_projection(bool isAsync) @@ -6717,7 +6667,7 @@ FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[FullName] <> N'Dom') AND ( SELECT TOP(1) [w].[Id] FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND ([w].[IsAutomatic] = CAST(1 AS bit)) + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND ([w].[IsAutomatic] = CAST(1 AS bit)) ORDER BY [w].[Id]) IS NOT NULL)"); } @@ -6730,7 +6680,7 @@ public override async Task Query_with_complex_let_containing_ordering_and_filter @"SELECT [g].[Nickname], ( SELECT TOP(1) [w].[Name] FROM [Weapons] AS [w] - WHERE (([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AND ([w].[IsAutomatic] = CAST(1 AS bit)) + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND ([w].[IsAutomatic] = CAST(1 AS bit)) ORDER BY [w].[AmmunitionType] DESC) AS [WeaponName] FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[Nickname] <> N'Dom')"); @@ -6758,9 +6708,9 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN [Squads] AS [s] ON [t0].[SquadId] = [s].[Id] -WHERE ((SUBSTRING([t].[Note], 0 + 1, CAST(LEN([s].[Name]) AS int)) = [t].[GearNickName]) AND (SUBSTRING([t].[Note], 0 + 1, CAST(LEN([s].[Name]) AS int)) IS NOT NULL AND [t].[GearNickName] IS NOT NULL)) OR (SUBSTRING([t].[Note], 0 + 1, CAST(LEN([s].[Name]) AS int)) IS NULL AND [t].[GearNickName] IS NULL)"); +WHERE (SUBSTRING([t].[Note], 0 + 1, CAST(LEN([s].[Name]) AS int)) = [t].[GearNickName]) OR (SUBSTRING([t].[Note], 0 + 1, CAST(LEN([s].[Name]) AS int)) IS NULL AND [t].[GearNickName] IS NULL)"); } public override async Task Filter_with_new_Guid(bool isAsync) @@ -6798,8 +6748,8 @@ public override async Task OfTypeNav1(bool isAsync) AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) -LEFT JOIN [Tags] AS [t0] ON (([g].[Nickname] = [t0].[GearNickName]) AND [t0].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t0].[GearSquadId]) AND [t0].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) +LEFT JOIN [Tags] AS [t0] ON ([g].[Nickname] = [t0].[GearNickName]) AND ([g].[SquadId] = [t0].[GearSquadId]) WHERE (([g].[Discriminator] IN (N'Gear', N'Officer') AND (([t].[Note] <> N'Foo') OR [t].[Note] IS NULL)) AND ([g].[Discriminator] = N'Officer')) AND (([t0].[Note] <> N'Bar') OR [t0].[Note] IS NULL)"); } @@ -6810,7 +6760,7 @@ public override async Task OfTypeNav2(bool isAsync) AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) LEFT JOIN [Cities] AS [c] ON [g].[AssignedCityName] = [c].[Name] WHERE (([g].[Discriminator] IN (N'Gear', N'Officer') AND (([t].[Note] <> N'Foo') OR [t].[Note] IS NULL)) AND ([g].[Discriminator] = N'Officer')) AND (([c].[Location] <> 'Bar') OR [c].[Location] IS NULL)"); } @@ -6822,9 +6772,9 @@ public override async Task OfTypeNav3(bool isAsync) AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t] ON (([g].[Nickname] = [t].[GearNickName]) AND [t].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t].[GearSquadId]) AND [t].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) INNER JOIN [Weapons] AS [w] ON [g].[FullName] = [w].[OwnerFullName] -LEFT JOIN [Tags] AS [t0] ON (([g].[Nickname] = [t0].[GearNickName]) AND [t0].[GearNickName] IS NOT NULL) AND (([g].[SquadId] = [t0].[GearSquadId]) AND [t0].[GearSquadId] IS NOT NULL) +LEFT JOIN [Tags] AS [t0] ON ([g].[Nickname] = [t0].[GearNickName]) AND ([g].[SquadId] = [t0].[GearSquadId]) WHERE (([g].[Discriminator] IN (N'Gear', N'Officer') AND (([t].[Note] <> N'Foo') OR [t].[Note] IS NULL)) AND ([g].[Discriminator] = N'Officer')) AND (([t0].[Note] <> N'Bar') OR [t0].[Note] IS NULL)"); } @@ -6920,7 +6870,7 @@ WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ORDER BY ( SELECT TOP(1) [w0].[Name] FROM [Weapons] AS [w0] - WHERE (([g].[FullName] = [w0].[OwnerFullName]) AND [w0].[OwnerFullName] IS NOT NULL) AND (CHARINDEX(N'Gnasher', [w0].[Name]) > 0)), [g].[Nickname], [g].[SquadId], [w].[Id]"); + WHERE ([g].[FullName] = [w0].[OwnerFullName]) AND (CHARINDEX(N'Gnasher', [w0].[Name]) > 0)), [g].[Nickname], [g].[SquadId], [w].[Id]"); } public override async Task Anonymous_projection_take_followed_by_projecting_single_element_from_collection_navigation(bool isAsync) @@ -7015,13 +6965,13 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) OUTER APPLY ( SELECT TOP(50) [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 [g0].[LeaderNickname] IS NOT NULL) AND (([t0].[SquadId] = [g0].[LeaderSquadId]) AND [t0].[SquadId] IS NOT NULL))) + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') AND ([t0].[Nickname] IS NOT NULL AND (([t0].[Nickname] = [g0].[LeaderNickname]) AND ([t0].[SquadId] = [g0].[LeaderSquadId]))) ) AS [t1] -WHERE ([t0].[Discriminator] = N'Officer') AND [t0].[Discriminator] IS NOT NULL +WHERE [t0].[Discriminator] = N'Officer' ORDER BY [t].[Id], [t1].[Nickname], [t1].[SquadId]"); } @@ -7036,13 +6986,13 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [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 +) AS [t1] ON (([t0].[Nickname] = [t1].[LeaderNickname]) OR ([t0].[Nickname] IS NULL AND [t1].[LeaderNickname] IS NULL)) AND ([t0].[SquadId] = [t1].[LeaderSquadId]) +WHERE [t0].[Discriminator] = N'Officer' ORDER BY [t].[Id], [t1].[Nickname], [t1].[SquadId]"); } @@ -7057,7 +7007,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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)) AND [t].[Note] IS NOT NULL +) AS [t0] ON ((([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId])) AND [t].[Note] IS NOT NULL) AND [t].[Note] IS NOT NULL ORDER BY [t].[Id], [t0].[Nickname], [t0].[SquadId]"); } @@ -7207,7 +7157,7 @@ INNER JOIN ( FROM [Gears] AS [g0] LEFT JOIN [Cities] AS [c] ON [g0].[AssignedCityName] = [c].[Name] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') AND ([g0].[Discriminator] = N'Officer') -) AS [t] ON (([g].[Nickname] = [t].[LeaderNickname]) AND [t].[LeaderNickname] IS NOT NULL) AND ([g].[SquadId] = [t].[LeaderSquadId]) +) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE [g].[Discriminator] = N'Officer'"); } @@ -7251,7 +7201,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN [Squads] AS [s] ON [t0].[SquadId] = [s].[Id] ORDER BY [t].[Note]"); } @@ -7270,7 +7220,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN ( SELECT [t1].[Nickname], [w].[Id], [w].[OwnerFullName] FROM [Weapons] AS [w] @@ -7341,7 +7291,7 @@ public override async Task Complex_GroupBy_after_set_operator(bool isAsync) SELECT [c].[Name], ( SELECT COUNT(*) FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AS [Count] + WHERE [g].[FullName] = [w].[OwnerFullName]) AS [Count] FROM [Gears] AS [g] LEFT JOIN [Cities] AS [c] ON [g].[AssignedCityName] = [c].[Name] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') @@ -7349,7 +7299,7 @@ UNION ALL SELECT [c0].[Name], ( SELECT COUNT(*) FROM [Weapons] AS [w0] - WHERE ([g0].[FullName] = [w0].[OwnerFullName]) AND [w0].[OwnerFullName] IS NOT NULL) AS [Count] + WHERE [g0].[FullName] = [w0].[OwnerFullName]) AS [Count] FROM [Gears] AS [g0] INNER JOIN [Cities] AS [c0] ON [g0].[CityOfBirthName] = [c0].[Name] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') @@ -7367,7 +7317,7 @@ public override async Task Complex_GroupBy_after_set_operator_using_result_selec SELECT [c].[Name], ( SELECT COUNT(*) FROM [Weapons] AS [w] - WHERE ([g].[FullName] = [w].[OwnerFullName]) AND [w].[OwnerFullName] IS NOT NULL) AS [Count] + WHERE [g].[FullName] = [w].[OwnerFullName]) AS [Count] FROM [Gears] AS [g] LEFT JOIN [Cities] AS [c] ON [g].[AssignedCityName] = [c].[Name] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') @@ -7375,7 +7325,7 @@ UNION ALL SELECT [c0].[Name], ( SELECT COUNT(*) FROM [Weapons] AS [w0] - WHERE ([g0].[FullName] = [w0].[OwnerFullName]) AND [w0].[OwnerFullName] IS NOT NULL) AS [Count] + WHERE [g0].[FullName] = [w0].[OwnerFullName]) AS [Count] FROM [Gears] AS [g0] INNER JOIN [Cities] AS [c0] ON [g0].[CityOfBirthName] = [c0].[Name] WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') @@ -7424,7 +7374,7 @@ LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [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) +) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN [Squads] AS [s] ON [t0].[SquadId] = [s].[Id] GROUP BY [t0].[HasSoulPatch], [s].[Name]"); } @@ -7514,19 +7464,23 @@ public override async Task Where_with_enum_flags_parameter(bool isAsync) FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] & @__rank_0) = @__rank_0)", // - @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] + @"@__rank_0=NULL (DbType = Int32) + +SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer')", +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND [g].[Rank] & @__rank_0 IS NULL", // @"@__rank_0='1' (Nullable = true) SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[Rank] | @__rank_0) <> @__rank_0)", +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ((([g].[Rank] | @__rank_0) <> @__rank_0) OR [g].[Rank] | @__rank_0 IS NULL)", // - @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] + @"@__rank_0=NULL (DbType = Int32) + +SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] -WHERE CAST(0 AS bit) = CAST(1 AS bit)"); +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND [g].[Rank] | @__rank_0 IS NOT NULL"); } public override async Task FirstOrDefault_navigation_access_entity_equality_in_where_predicate_apply_peneding_selector(bool isAsync) @@ -7537,17 +7491,12 @@ public override async Task FirstOrDefault_navigation_access_entity_equality_in_w @"SELECT [f].[Id], [f].[CapitalName], [f].[Discriminator], [f].[Name], [f].[CommanderName], [f].[Eradicated] FROM [Factions] AS [f] LEFT JOIN [Cities] AS [c] ON [f].[CapitalName] = [c].[Name] -WHERE ([f].[Discriminator] = N'LocustHorde') AND ((([c].[Name] = ( - SELECT TOP(1) [c0].[Name] - FROM [Gears] AS [g] - INNER JOIN [Cities] AS [c0] ON [g].[CityOfBirthName] = [c0].[Name] - WHERE [g].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g].[Nickname])) AND ([c].[Name] IS NOT NULL AND ( +WHERE ([f].[Discriminator] = N'LocustHorde') AND (([c].[Name] = ( SELECT TOP(1) [c0].[Name] FROM [Gears] AS [g] INNER JOIN [Cities] AS [c0] ON [g].[CityOfBirthName] = [c0].[Name] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') - ORDER BY [g].[Nickname]) IS NOT NULL)) OR ([c].[Name] IS NULL AND ( + ORDER BY [g].[Nickname])) OR ([c].[Name] IS NULL AND ( SELECT TOP(1) [c0].[Name] FROM [Gears] AS [g] INNER JOIN [Cities] AS [c0] ON [g].[CityOfBirthName] = [c0].[Name] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GroupByQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GroupByQuerySqlServerTest.cs index 36651bdbfb1..d245ef8ec17 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GroupByQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GroupByQuerySqlServerTest.cs @@ -1098,11 +1098,11 @@ public override async Task Union_simple_groupby(bool isAsync) FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] - WHERE ([c].[ContactTitle] = N'Owner') AND [c].[ContactTitle] IS NOT NULL + WHERE [c].[ContactTitle] = N'Owner' UNION SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] - WHERE ([c0].[City] = N'México D.F.') AND [c0].[City] IS NOT NULL + WHERE [c0].[City] = N'México D.F.' ) AS [t] GROUP BY [t].[City]"); } @@ -1255,7 +1255,7 @@ public override async Task GroupBy_filter_key(bool isAsync) @"SELECT [o].[CustomerID] AS [Key], COUNT(*) AS [c] FROM [Orders] AS [o] GROUP BY [o].[CustomerID] -HAVING ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL"); +HAVING [o].[CustomerID] = N'ALFKI'"); } public override async Task GroupBy_filter_count(bool isAsync) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/IncludeAsyncSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/IncludeAsyncSqlServerTest.cs index caf59e572db..9d925cb4616 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/IncludeAsyncSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/IncludeAsyncSqlServerTest.cs @@ -26,14 +26,14 @@ public override async Task Include_collection_order_by_subquery() SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], ( SELECT TOP(1) [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[EmployeeID]) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] = N'ALFKI' ORDER BY ( SELECT TOP(1) [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[EmployeeID]) ) AS [t] LEFT JOIN [Orders] AS [o0] ON [t].[CustomerID] = [o0].[CustomerID] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/IncludeSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/IncludeSqlServerTest.cs index 31bf82b5722..0720a5c8378 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/IncludeSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/IncludeSqlServerTest.cs @@ -261,14 +261,14 @@ public override void Include_collection_order_by_collection_column(bool useStrin SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], ( SELECT TOP(1) [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderDate] DESC) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'W%' ORDER BY ( SELECT TOP(1) [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderDate] DESC) DESC ) AS [t] LEFT JOIN [Orders] AS [o0] ON [t].[CustomerID] = [o0].[CustomerID] @@ -360,14 +360,14 @@ public override void Include_collection_order_by_subquery(bool useString) SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], ( SELECT TOP(1) [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[EmployeeID]) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] = N'ALFKI' ORDER BY ( SELECT TOP(1) [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[EmployeeID]) ) AS [t] LEFT JOIN [Orders] AS [o0] ON [t].[CustomerID] = [o0].[CustomerID] @@ -853,7 +853,7 @@ public override void Include_reference_with_filter_reordered(bool useString) @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL"); +WHERE [o].[CustomerID] = N'ALFKI'"); } public override void Include_reference_with_filter(bool useString) @@ -864,7 +864,7 @@ public override void Include_reference_with_filter(bool useString) @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL"); +WHERE [o].[CustomerID] = N'ALFKI'"); } public override void Include_collection_dependent_already_tracked_as_no_tracking(bool useString) @@ -874,7 +874,7 @@ public override void Include_collection_dependent_already_tracked_as_no_tracking AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL", +WHERE [o].[CustomerID] = N'ALFKI'", // @"SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( @@ -893,7 +893,7 @@ public override void Include_collection_dependent_already_tracked(bool useString AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL", +WHERE [o].[CustomerID] = N'ALFKI'", // @"SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( @@ -912,7 +912,7 @@ public override void Include_reference_dependent_already_tracked(bool useString) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL", +WHERE [o].[CustomerID] = N'ALFKI'", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Orders] AS [o] @@ -964,12 +964,12 @@ public override void Include_with_complex_projection_does_not_change_ordering_of @"SELECT [c].[CustomerID] AS [Id], ( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AS [TotalOrders] + WHERE [c].[CustomerID] = [o].[CustomerID]) AS [TotalOrders] FROM [Customers] AS [c] -WHERE (([c].[ContactTitle] = N'Owner') AND [c].[ContactTitle] IS NOT NULL) AND (( +WHERE ([c].[ContactTitle] = N'Owner') AND (( SELECT COUNT(*) FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL) > 2) + WHERE [c].[CustomerID] = [o0].[CustomerID]) > 2) ORDER BY [c].[CustomerID]"); } @@ -1051,14 +1051,14 @@ public override void Then_include_collection_order_by_collection_column(bool use SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], ( SELECT TOP(1) [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderDate] DESC) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'W%' ORDER BY ( SELECT TOP(1) [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderDate] DESC) DESC ) AS [t] LEFT JOIN ( diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/InheritanceSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/InheritanceSqlServerTest.cs index 0889099f460..75683b321a1 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/InheritanceSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/InheritanceSqlServerTest.cs @@ -243,7 +243,7 @@ public override void Can_filter_all_animals() AssertSql( @"SELECT [a].[Species], [a].[CountryId], [a].[Discriminator], [a].[Name], [a].[EagleId], [a].[IsFlightless], [a].[Group], [a].[FoundOn] FROM [Animal] AS [a] -WHERE [a].[Discriminator] IN (N'Eagle', N'Kiwi') AND (([a].[Name] = N'Great spotted kiwi') AND [a].[Name] IS NOT NULL) +WHERE [a].[Discriminator] IN (N'Eagle', N'Kiwi') AND ([a].[Name] = N'Great spotted kiwi') ORDER BY [a].[Species]"); } @@ -320,7 +320,7 @@ public override void Can_use_of_type_kiwi_where_north_on_derived_property() AssertSql( @"SELECT [a].[Species], [a].[CountryId], [a].[Discriminator], [a].[Name], [a].[EagleId], [a].[IsFlightless], [a].[FoundOn] FROM [Animal] AS [a] -WHERE ([a].[Discriminator] IN (N'Eagle', N'Kiwi') AND ([a].[Discriminator] = N'Kiwi')) AND (([a].[FoundOn] = CAST(0 AS tinyint)) AND [a].[FoundOn] IS NOT NULL)"); +WHERE ([a].[Discriminator] IN (N'Eagle', N'Kiwi') AND ([a].[Discriminator] = N'Kiwi')) AND ([a].[FoundOn] = CAST(0 AS tinyint))"); } public override void Can_use_of_type_kiwi_where_south_on_derived_property() @@ -330,7 +330,7 @@ public override void Can_use_of_type_kiwi_where_south_on_derived_property() AssertSql( @"SELECT [a].[Species], [a].[CountryId], [a].[Discriminator], [a].[Name], [a].[EagleId], [a].[IsFlightless], [a].[FoundOn] FROM [Animal] AS [a] -WHERE ([a].[Discriminator] IN (N'Eagle', N'Kiwi') AND ([a].[Discriminator] = N'Kiwi')) AND (([a].[FoundOn] = CAST(1 AS tinyint)) AND [a].[FoundOn] IS NOT NULL)"); +WHERE ([a].[Discriminator] IN (N'Eagle', N'Kiwi') AND ([a].[Discriminator] = N'Kiwi')) AND ([a].[FoundOn] = CAST(1 AS tinyint))"); } public override void Discriminator_used_when_projection_over_derived_type() diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs index fd40ea0bc79..3f6780359fb 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs @@ -28,15 +28,15 @@ FROM [Entities1] AS [e] // @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[BoolA] = [e].[NullableBoolB]) AND [e].[NullableBoolB] IS NOT NULL", +WHERE [e].[BoolA] = [e].[NullableBoolB]", // @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[NullableBoolA] = [e].[BoolB]) AND [e].[NullableBoolA] IS NOT NULL", +WHERE [e].[NullableBoolA] = [e].[BoolB]", // @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE (([e].[NullableBoolA] = [e].[NullableBoolB]) AND ([e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL)) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL)"); +WHERE ([e].[NullableBoolA] = [e].[NullableBoolB]) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL)"); } public override void Compare_negated_bool_with_bool_equal() @@ -380,15 +380,15 @@ FROM [Entities1] AS [e] // @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[BoolA] = [e].[NullableBoolB]) AND [e].[NullableBoolB] IS NOT NULL", +WHERE [e].[BoolA] = [e].[NullableBoolB]", // @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[NullableBoolA] = [e].[BoolB]) AND [e].[NullableBoolA] IS NOT NULL", +WHERE [e].[NullableBoolA] = [e].[BoolB]", // @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE (([e].[NullableBoolA] = [e].[NullableBoolB]) AND ([e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL)) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL)"); +WHERE ([e].[NullableBoolA] = [e].[NullableBoolB]) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL)"); } public override void Compare_equals_method_static() @@ -402,15 +402,15 @@ FROM [Entities1] AS [e] // @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[BoolA] = [e].[NullableBoolB]) AND [e].[NullableBoolB] IS NOT NULL", +WHERE [e].[BoolA] = [e].[NullableBoolB]", // @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[NullableBoolA] = [e].[BoolB]) AND [e].[NullableBoolA] IS NOT NULL", +WHERE [e].[NullableBoolA] = [e].[BoolB]", // @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE (([e].[NullableBoolA] = [e].[NullableBoolB]) AND ([e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL)) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL)"); +WHERE ([e].[NullableBoolA] = [e].[NullableBoolB]) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL)"); } public override void Compare_equals_method_negated() @@ -692,7 +692,7 @@ public override void Compare_nullable_with_non_null_parameter_not_equal() SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[NullableStringA] = @__prm_0) AND [e].[NullableStringA] IS NOT NULL"); +WHERE [e].[NullableStringA] = @__prm_0"); } public override void Join_uses_database_semantics() @@ -750,7 +750,7 @@ public override void Where_multiple_ors_with_null() AssertSql( @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ((([e].[NullableStringA] = N'Foo') AND [e].[NullableStringA] IS NOT NULL) OR (([e].[NullableStringA] = N'Blah') AND [e].[NullableStringA] IS NOT NULL)) OR [e].[NullableStringA] IS NULL"); +WHERE (([e].[NullableStringA] = N'Foo') OR ([e].[NullableStringA] = N'Blah')) OR [e].[NullableStringA] IS NULL"); } public override void Where_multiple_ands_with_null() @@ -770,7 +770,7 @@ public override void Where_multiple_ors_with_nullable_parameter() AssertSql( @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE (([e].[NullableStringA] = N'Foo') AND [e].[NullableStringA] IS NOT NULL) OR [e].[NullableStringA] IS NULL"); +WHERE ([e].[NullableStringA] = N'Foo') OR [e].[NullableStringA] IS NULL"); } public override void Where_multiple_ands_with_nullable_parameter_and_constant() @@ -834,7 +834,7 @@ public override void Where_equal_with_coalesce() AssertSql( @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ((COALESCE([e].[NullableStringA], [e].[NullableStringB]) = [e].[NullableStringC]) AND (([e].[NullableStringA] IS NOT NULL OR [e].[NullableStringB] IS NOT NULL) AND [e].[NullableStringC] IS NOT NULL)) OR (([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) AND [e].[NullableStringC] IS NULL)"); +WHERE (COALESCE([e].[NullableStringA], [e].[NullableStringB]) = [e].[NullableStringC]) OR (([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) AND [e].[NullableStringC] IS NULL)"); } public override void Where_not_equal_with_coalesce() @@ -854,7 +854,7 @@ public override void Where_equal_with_coalesce_both_sides() AssertSql( @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE (COALESCE([e].[NullableStringA], [e].[NullableStringB]) = COALESCE([e].[StringA], [e].[StringB])) AND ([e].[NullableStringA] IS NOT NULL OR [e].[NullableStringB] IS NOT NULL)"); +WHERE COALESCE([e].[NullableStringA], [e].[NullableStringB]) = COALESCE([e].[StringA], [e].[StringB])"); } public override void Where_not_equal_with_coalesce_both_sides() @@ -892,13 +892,13 @@ public override void Where_not_equal_with_conditional() @"SELECT [e].[Id] FROM [Entities1] AS [e] WHERE (([e].[NullableStringC] <> CASE - WHEN (([e].[NullableStringA] = [e].[NullableStringB]) AND ([e].[NullableStringA] IS NOT NULL AND [e].[NullableStringB] IS NOT NULL)) OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) THEN [e].[NullableStringA] + WHEN ([e].[NullableStringA] = [e].[NullableStringB]) OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) THEN [e].[NullableStringA] ELSE [e].[NullableStringB] END) OR ([e].[NullableStringC] IS NULL OR CASE - WHEN (([e].[NullableStringA] = [e].[NullableStringB]) AND ([e].[NullableStringA] IS NOT NULL AND [e].[NullableStringB] IS NOT NULL)) OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) THEN [e].[NullableStringA] + WHEN ([e].[NullableStringA] = [e].[NullableStringB]) OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) THEN [e].[NullableStringA] ELSE [e].[NullableStringB] END IS NULL)) AND ([e].[NullableStringC] IS NOT NULL OR CASE - WHEN (([e].[NullableStringA] = [e].[NullableStringB]) AND ([e].[NullableStringA] IS NOT NULL AND [e].[NullableStringB] IS NOT NULL)) OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) THEN [e].[NullableStringA] + WHEN ([e].[NullableStringA] = [e].[NullableStringB]) OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) THEN [e].[NullableStringA] ELSE [e].[NullableStringB] END IS NOT NULL)"); } @@ -911,7 +911,7 @@ public override void Where_equal_with_conditional_non_nullable() @"SELECT [e].[Id] FROM [Entities1] AS [e] WHERE ([e].[NullableStringC] <> CASE - WHEN (([e].[NullableStringA] = [e].[NullableStringB]) AND ([e].[NullableStringA] IS NOT NULL AND [e].[NullableStringB] IS NOT NULL)) OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) THEN [e].[StringA] + WHEN ([e].[NullableStringA] = [e].[NullableStringB]) OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) THEN [e].[StringA] ELSE [e].[StringB] END) OR [e].[NullableStringC] IS NULL"); } @@ -923,7 +923,7 @@ public override void Where_equal_with_and_and_contains() AssertSql( @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ((([e].[NullableStringB] = N'') AND [e].[NullableStringB] IS NOT NULL) OR (CHARINDEX([e].[NullableStringB], [e].[NullableStringA]) > 0)) AND ([e].[BoolA] = CAST(1 AS bit))"); +WHERE (([e].[NullableStringB] = N'') OR (CHARINDEX([e].[NullableStringB], [e].[NullableStringA]) > 0)) AND ([e].[BoolA] = CAST(1 AS bit))"); } public override void Null_comparison_in_selector_with_relational_nulls() @@ -1020,7 +1020,7 @@ public override void Where_nullable_bool_equal_with_constant() AssertSql( @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[NullableBoolA] = CAST(1 AS bit)) AND [e].[NullableBoolA] IS NOT NULL"); +WHERE [e].[NullableBoolA] = CAST(1 AS bit)"); } public override void Where_nullable_bool_with_null_check() @@ -1038,11 +1038,9 @@ public override void Where_equal_using_relational_null_semantics_with_parameter( base.Where_equal_using_relational_null_semantics_with_parameter(); AssertSql( - @"@__prm_0=NULL - -SELECT [e].[Id] + @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableBoolA] = @__prm_0"); +WHERE [e].[NullableBoolA] IS NULL"); } public override void Where_equal_using_relational_null_semantics_complex_with_parameter() @@ -1070,11 +1068,9 @@ public override void Where_not_equal_using_relational_null_semantics_with_parame base.Where_not_equal_using_relational_null_semantics_with_parameter(); AssertSql( - @"@__prm_0=NULL - -SELECT [e].[Id] + @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableBoolA] <> @__prm_0"); +WHERE [e].[NullableBoolA] IS NOT NULL"); } public override void Where_not_equal_using_relational_null_semantics_complex_with_parameter() @@ -1158,7 +1154,7 @@ public override void Switching_null_semantics_produces_different_cache_entry() AssertSql( @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE (([e].[NullableBoolA] = [e].[NullableBoolB]) AND ([e].[NullableBoolA] IS NOT NULL AND [e].[NullableBoolB] IS NOT NULL)) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL)", +WHERE ([e].[NullableBoolA] = [e].[NullableBoolB]) OR ([e].[NullableBoolA] IS NULL AND [e].[NullableBoolB] IS NULL)", // @"SELECT [e].[Id] FROM [Entities1] AS [e] @@ -1258,7 +1254,7 @@ public override void Null_semantics_applied_when_comparing_two_functions_with_mu AssertSql( @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ((REPLACE([e].[NullableStringA], [e].[NullableStringB], [e].[NullableStringC]) = [e].[NullableStringA]) AND (REPLACE([e].[NullableStringA], [e].[NullableStringB], [e].[NullableStringC]) IS NOT NULL AND [e].[NullableStringA] IS NOT NULL)) OR (REPLACE([e].[NullableStringA], [e].[NullableStringB], [e].[NullableStringC]) IS NULL AND [e].[NullableStringA] IS NULL)", +WHERE (REPLACE([e].[NullableStringA], [e].[NullableStringB], [e].[NullableStringC]) = [e].[NullableStringA]) OR (REPLACE([e].[NullableStringA], [e].[NullableStringB], [e].[NullableStringC]) IS NULL AND [e].[NullableStringA] IS NULL)", // @"SELECT [e].[Id] FROM [Entities1] AS [e] @@ -1272,11 +1268,11 @@ public override void Null_semantics_coalesce() AssertSql( @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[NullableBoolA] = COALESCE([e].[NullableBoolB], [e].[BoolC])) AND [e].[NullableBoolA] IS NOT NULL", +WHERE [e].[NullableBoolA] = COALESCE([e].[NullableBoolB], [e].[BoolC])", // @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE (([e].[NullableBoolA] = COALESCE([e].[NullableBoolB], [e].[NullableBoolC])) AND ([e].[NullableBoolA] IS NOT NULL AND ([e].[NullableBoolB] IS NOT NULL OR [e].[NullableBoolC] IS NOT NULL))) OR ([e].[NullableBoolA] IS NULL AND ([e].[NullableBoolB] IS NULL AND [e].[NullableBoolC] IS NULL))", +WHERE ([e].[NullableBoolA] = COALESCE([e].[NullableBoolB], [e].[NullableBoolC])) OR ([e].[NullableBoolA] IS NULL AND ([e].[NullableBoolB] IS NULL AND [e].[NullableBoolC] IS NULL))", // @"SELECT [e].[Id] FROM [Entities1] AS [e] @@ -1294,13 +1290,10 @@ public override void Null_semantics_conditional() AssertSql( @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE ([e].[BoolA] = CASE - WHEN [e].[BoolB] = CAST(1 AS bit) THEN [e].[NullableBoolB] - ELSE [e].[NullableBoolC] -END) AND CASE +WHERE [e].[BoolA] = CASE WHEN [e].[BoolB] = CAST(1 AS bit) THEN [e].[NullableBoolB] ELSE [e].[NullableBoolC] -END IS NOT NULL", +END", // @"SELECT [e].[Id] FROM [Entities1] AS [e] @@ -1360,7 +1353,7 @@ public override void Null_semantics_with_null_check_simple() AssertSql( @"SELECT [e].[Id], [e].[BoolA], [e].[BoolB], [e].[BoolC], [e].[IntA], [e].[IntB], [e].[IntC], [e].[NullableBoolA], [e].[NullableBoolB], [e].[NullableBoolC], [e].[NullableIntA], [e].[NullableIntB], [e].[NullableIntC], [e].[NullableStringA], [e].[NullableStringB], [e].[NullableStringC], [e].[StringA], [e].[StringB], [e].[StringC] FROM [Entities1] AS [e] -WHERE [e].[NullableIntA] IS NOT NULL AND (([e].[NullableIntA] = [e].[NullableIntB]) AND [e].[NullableIntB] IS NOT NULL)", +WHERE [e].[NullableIntA] IS NOT NULL AND ([e].[NullableIntA] = [e].[NullableIntB])", // @"SELECT [e].[Id], [e].[BoolA], [e].[BoolB], [e].[BoolC], [e].[IntA], [e].[IntB], [e].[IntC], [e].[NullableBoolA], [e].[NullableBoolB], [e].[NullableBoolC], [e].[NullableIntA], [e].[NullableIntB], [e].[NullableIntC], [e].[NullableStringA], [e].[NullableStringB], [e].[NullableStringC], [e].[StringA], [e].[StringB], [e].[StringC] FROM [Entities1] AS [e] @@ -1394,7 +1387,7 @@ WHERE [e].[NullableIntA] IS NOT NULL AND ((([e].[NullableIntC] <> [e].[NullableI // @"SELECT [e].[Id], [e].[BoolA], [e].[BoolB], [e].[BoolC], [e].[IntA], [e].[IntB], [e].[IntC], [e].[NullableBoolA], [e].[NullableBoolB], [e].[NullableBoolC], [e].[NullableIntA], [e].[NullableIntB], [e].[NullableIntC], [e].[NullableStringA], [e].[NullableStringB], [e].[NullableStringC], [e].[StringA], [e].[StringB], [e].[StringC] FROM [Entities1] AS [e] -WHERE ([e].[NullableIntA] IS NOT NULL OR [e].[NullableIntB] IS NOT NULL) AND ((([e].[NullableIntA] = [e].[NullableIntC]) AND ([e].[NullableIntA] IS NOT NULL AND [e].[NullableIntC] IS NOT NULL)) OR ([e].[NullableIntA] IS NULL AND [e].[NullableIntC] IS NULL))"); +WHERE ([e].[NullableIntA] IS NOT NULL OR [e].[NullableIntB] IS NOT NULL) AND (([e].[NullableIntA] = [e].[NullableIntC]) OR ([e].[NullableIntA] IS NULL AND [e].[NullableIntC] IS NULL))"); } public override void IsNull_on_complex_expression() diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs index 9fe2d24a306..489fe489db6 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs @@ -711,7 +711,7 @@ WHERE [o4].[Discriminator] IN (N'OwnedPerson', N'Branch', N'LeafB', N'LeafA') ) AS [t2] ON [o2].[Id] = [t2].[Id] WHERE [o2].[PersonAddress_Country_PlanetId] IS NOT NULL ) AS [t3] ON [t0].[Id] = [t3].[Id] -WHERE [o].[Discriminator] IN (N'OwnedPerson', N'Branch', N'LeafB', N'LeafA') AND (([t3].[PersonAddress_Country_Name] = N'USA') AND [t3].[PersonAddress_Country_Name] IS NOT NULL)"); +WHERE [o].[Discriminator] IN (N'OwnedPerson', N'Branch', N'LeafB', N'LeafA') AND ([t3].[PersonAddress_Country_Name] = N'USA')"); } public override async Task Navigation_rewrite_on_owned_reference_projecting_entity(bool isAsync) @@ -814,7 +814,7 @@ FROM [OwnedPerson] AS [o19] WHERE [o17].[LeafAAddress_Country_PlanetId] IS NOT NULL ) AS [t18] ON [t15].[Id] = [t18].[Id] LEFT JOIN [Order] AS [o20] ON [o].[Id] = [o20].[ClientId] -WHERE [o].[Discriminator] IN (N'OwnedPerson', N'Branch', N'LeafB', N'LeafA') AND (([t3].[PersonAddress_Country_Name] = N'USA') AND [t3].[PersonAddress_Country_Name] IS NOT NULL) +WHERE [o].[Discriminator] IN (N'OwnedPerson', N'Branch', N'LeafB', N'LeafA') AND ([t3].[PersonAddress_Country_Name] = N'USA') ORDER BY [o].[Id], [o20].[ClientId], [o20].[Id]"); } @@ -1432,7 +1432,7 @@ WHERE [o2].[PersonAddress_Country_PlanetId] IS NOT NULL LEFT JOIN [Planet] AS [p] ON [t3].[PersonAddress_Country_PlanetId] = [p].[Id] LEFT JOIN [Star] AS [s] ON [p].[StarId] = [s].[Id] LEFT JOIN [Element] AS [e] ON [s].[Id] = [e].[StarId] -WHERE [o].[Discriminator] IN (N'OwnedPerson', N'Branch', N'LeafB', N'LeafA') AND (([s].[Name] = N'Sol') AND [s].[Name] IS NOT NULL) +WHERE [o].[Discriminator] IN (N'OwnedPerson', N'Branch', N'LeafB', N'LeafA') AND ([s].[Name] = N'Sol') ORDER BY [o].[Id], [e].[Id]"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs index b2cad03cbb1..6bc15fc9cec 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs @@ -104,7 +104,7 @@ public async Task Where_not_equals_DateTime_Now(bool async) AssertSql( @"SELECT [d].[Id], [d].[DateTime], [d].[DateTime2], [d].[DateTime2_0], [d].[DateTime2_1], [d].[DateTime2_2], [d].[DateTime2_3], [d].[DateTime2_4], [d].[DateTime2_5], [d].[DateTime2_6], [d].[DateTime2_7], [d].[SmallDateTime] FROM [Dates] AS [d] -WHERE ((([d].[DateTime2_2] <> GETDATE()) AND ([d].[DateTime2_7] <> GETDATE())) AND ([d].[DateTime] <> GETDATE())) AND ([d].[SmallDateTime] <> GETDATE())"); +WHERE (((([d].[DateTime2_2] <> GETDATE()) OR GETDATE() IS NULL) AND (([d].[DateTime2_7] <> GETDATE()) OR GETDATE() IS NULL)) AND (([d].[DateTime] <> GETDATE()) OR GETDATE() IS NULL)) AND (([d].[SmallDateTime] <> GETDATE()) OR GETDATE() IS NULL)"); } } } @@ -589,7 +589,7 @@ public void Include_on_entity_with_composite_key_One_To_Many_bugs_925_926() AssertSql( @"SELECT [c].[FirstName], [c].[LastName], [o].[Id], [o].[CustomerFirstName], [o].[CustomerLastName], [o].[Name] FROM [Customer] AS [c] -LEFT JOIN [Order] AS [o] ON (([c].[FirstName] = [o].[CustomerFirstName]) AND [o].[CustomerFirstName] IS NOT NULL) AND (([c].[LastName] = [o].[CustomerLastName]) AND [o].[CustomerLastName] IS NOT NULL) +LEFT JOIN [Order] AS [o] ON ([c].[FirstName] = [o].[CustomerFirstName]) AND ([c].[LastName] = [o].[CustomerLastName]) ORDER BY [c].[FirstName], [c].[LastName], [o].[Id]"); } } @@ -615,7 +615,7 @@ public void Include_on_entity_with_composite_key_Many_To_One_bugs_925_926() AssertSql( @"SELECT [o].[Id], [o].[CustomerFirstName], [o].[CustomerLastName], [o].[Name], [c].[FirstName], [c].[LastName] FROM [Order] AS [o] -LEFT JOIN [Customer] AS [c] ON (([o].[CustomerFirstName] = [c].[FirstName]) AND [o].[CustomerFirstName] IS NOT NULL) AND (([o].[CustomerLastName] = [c].[LastName]) AND [o].[CustomerLastName] IS NOT NULL)"); +LEFT JOIN [Customer] AS [c] ON ([o].[CustomerFirstName] = [c].[FirstName]) AND ([o].[CustomerLastName] = [c].[LastName])"); } } } @@ -2398,7 +2398,7 @@ public virtual void Relational_command_cache_creates_new_entry_when_parameter_nu SELECT [e].[Id], [e].[Name] FROM [Entities] AS [e] -WHERE ([e].[Name] = @__name_0) AND [e].[Name] IS NOT NULL", +WHERE [e].[Name] = @__name_0", // @"SELECT [e].[Id], [e].[Name] FROM [Entities] AS [e] @@ -5439,7 +5439,7 @@ FROM [BuildingSet] AS [b] INNER JOIN [Builder] AS [b0] ON [b].[BuilderId] = [b0].[Id] INNER JOIN [City] AS [c] ON [b0].[CityId] = [c].[Id] INNER JOIN [MandatorSet] AS [m] ON [b].[MandatorId] = [m].[Id] -WHERE ([c].[Name] = N'Leeds') AND [c].[Name] IS NOT NULL"); +WHERE [c].[Name] = N'Leeds'"); } } } @@ -5964,7 +5964,7 @@ FROM [RemovableEntities] AS [r0] INNER JOIN [RemovableEntities] AS [r1] ON [r0].[Id] = [r1].[Id] WHERE [r0].[OwnedEntity_OwnedValue] IS NOT NULL ) AS [t] ON [r].[Id] = [t].[Id] -WHERE ([t].[OwnedEntity_OwnedValue] = N'Abc') AND [t].[OwnedEntity_OwnedValue] IS NOT NULL"); +WHERE [t].[OwnedEntity_OwnedValue] = N'Abc'"); } } } @@ -6088,7 +6088,7 @@ public virtual void Implicit_cast_6864() AssertSql( @"SELECT [f].[Id], [f].[String] FROM [Foos] AS [f] -WHERE ([f].[String] = N'1337') AND [f].[String] IS NOT NULL"); +WHERE [f].[String] = N'1337'"); } } } @@ -6109,7 +6109,7 @@ public virtual void Access_property_of_closure_6864() SELECT [f].[Id], [f].[String] FROM [Foos] AS [f] -WHERE ([f].[String] = @__bar_Value_0) AND [f].[String] IS NOT NULL"); +WHERE [f].[String] = @__bar_Value_0"); } } } @@ -6130,7 +6130,7 @@ public virtual void Call_method_on_closure_6864() SELECT [f].[Id], [f].[String] FROM [Foos] AS [f] -WHERE ([f].[String] = @__ToString_0) AND [f].[String] IS NOT NULL"); +WHERE [f].[String] = @__ToString_0"); } } } @@ -6151,7 +6151,7 @@ public virtual void Implicitly_cast_closure_6864() SELECT [f].[Id], [f].[String] FROM [Foos] AS [f] -WHERE ([f].[String] = @__p_0) AND [f].[String] IS NOT NULL"); +WHERE [f].[String] = @__p_0"); } } } @@ -6169,7 +6169,7 @@ public virtual void Implicitly_cast_return_value_6864() AssertSql( @"SELECT [f].[Id], [f].[String] FROM [Foos] AS [f] -WHERE ([f].[String] = N'1337') AND [f].[String] IS NOT NULL"); +WHERE [f].[String] = N'1337'"); } } } @@ -6540,16 +6540,13 @@ FROM [Things] AS [t] WHERE ( SELECT TOP(1) [v].[Id] FROM [Values] AS [v] - WHERE ([e].[Id] = [v].[Entity11023Id]) AND [v].[Entity11023Id] IS NOT NULL) IS NOT NULL AND (((( + WHERE [e].[Id] = [v].[Entity11023Id]) IS NOT NULL AND ((( SELECT TOP(1) [v0].[Id] FROM [Values] AS [v0] - WHERE ([e].[Id] = [v0].[Entity11023Id]) AND [v0].[Entity11023Id] IS NOT NULL) = [t].[Value11023Id]) AND (( + WHERE [e].[Id] = [v0].[Entity11023Id]) = [t].[Value11023Id]) OR (( SELECT TOP(1) [v0].[Id] FROM [Values] AS [v0] - WHERE ([e].[Id] = [v0].[Entity11023Id]) AND [v0].[Entity11023Id] IS NOT NULL) IS NOT NULL AND [t].[Value11023Id] IS NOT NULL)) OR (( - SELECT TOP(1) [v0].[Id] - FROM [Values] AS [v0] - WHERE ([e].[Id] = [v0].[Entity11023Id]) AND [v0].[Entity11023Id] IS NOT NULL) IS NULL AND [t].[Value11023Id] IS NULL)) + WHERE [e].[Id] = [v0].[Entity11023Id]) IS NULL AND [t].[Value11023Id] IS NULL)) ) AS [t0] ORDER BY [e].[Id], [t0].[Id]"); } @@ -6816,13 +6813,10 @@ OUTER APPLY ( SELECT [a1].[Id], [a1].[ActivityTypeId], [a1].[CompetitionSeasonId], [a1].[Points], [c0].[Id] AS [Id0] FROM [ActivityTypePoints12456] AS [a1] INNER JOIN [CompetitionSeasons] AS [c0] ON [a1].[CompetitionSeasonId] = [c0].[Id] - WHERE (([c0].[Id] = ( - SELECT TOP(1) [c1].[Id] - FROM [CompetitionSeasons] AS [c1] - WHERE ([c1].[StartDate] <= [a].[DateTime]) AND ([a].[DateTime] < [c1].[EndDate]))) AND ( + WHERE ([c0].[Id] = ( SELECT TOP(1) [c1].[Id] FROM [CompetitionSeasons] AS [c1] - WHERE ([c1].[StartDate] <= [a].[DateTime]) AND ([a].[DateTime] < [c1].[EndDate])) IS NOT NULL) AND ([a0].[Id] = [a1].[ActivityTypeId]) + WHERE ([c1].[StartDate] <= [a].[DateTime]) AND ([a].[DateTime] < [c1].[EndDate]))) AND ([a0].[Id] = [a1].[ActivityTypeId]) ) AS [t] ORDER BY [a].[Id], [a0].[Id], [t].[Id], [t].[Id0]"); } @@ -6863,13 +6857,10 @@ FROM [CompetitionSeasons] AS [c] SELECT TOP(1) [a].[Points] FROM [ActivityTypePoints12456] AS [a] INNER JOIN [CompetitionSeasons] AS [c0] ON [a].[CompetitionSeasonId] = [c0].[Id] - WHERE ([a1].[Id] = [a].[ActivityTypeId]) AND (([c0].[Id] = ( - SELECT TOP(1) [c1].[Id] - FROM [CompetitionSeasons] AS [c1] - WHERE ([c1].[StartDate] <= [a0].[DateTime]) AND ([a0].[DateTime] < [c1].[EndDate]))) AND ( + WHERE ([a1].[Id] = [a].[ActivityTypeId]) AND ([c0].[Id] = ( SELECT TOP(1) [c1].[Id] FROM [CompetitionSeasons] AS [c1] - WHERE ([c1].[StartDate] <= [a0].[DateTime]) AND ([a0].[DateTime] < [c1].[EndDate])) IS NOT NULL))) AS [Points] + WHERE ([c1].[StartDate] <= [a0].[DateTime]) AND ([a0].[DateTime] < [c1].[EndDate]))))) AS [Points] FROM [Activities] AS [a0] INNER JOIN [ActivityType12456] AS [a1] ON [a0].[ActivityTypeId] = [a1].[Id]"); } @@ -6983,7 +6974,7 @@ LEFT JOIN ( WHEN COALESCE(( SELECT MAX([d].[GameNumber]) FROM [DbGame] AS [d] - WHERE [d2].[Id] IS NOT NULL AND (([d2].[Id] = [d].[SeasonId]) AND [d].[SeasonId] IS NOT NULL)), 0) > 10 THEN CAST(1 AS bit) + WHERE [d2].[Id] IS NOT NULL AND ([d2].[Id] = [d].[SeasonId])), 0) > 10 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [c], [d0].[DbTradeId] FROM [DbTradeAsset] AS [d0] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/QueryNavigationsSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/QueryNavigationsSqlServerTest.cs index 6d0e6309598..2b5f9f3663f 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/QueryNavigationsSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/QueryNavigationsSqlServerTest.cs @@ -75,7 +75,7 @@ public override async Task Select_Where_Navigation(bool isAsync) @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] -WHERE ([c].[City] = N'Seattle') AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = N'Seattle'"); } public override async Task Select_Where_Navigation_Contains(bool isAsync) @@ -100,7 +100,7 @@ SELECT TOP(@__p_0) [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity FROM [Order Details] AS [o] INNER JOIN [Orders] AS [o0] ON [o].[OrderID] = [o0].[OrderID] LEFT JOIN [Customers] AS [c] ON [o0].[CustomerID] = [c].[CustomerID] -WHERE ([c].[City] = N'Seattle') AND [c].[City] IS NOT NULL +WHERE [c].[City] = N'Seattle' ORDER BY [o].[OrderID], [o].[ProductID]"); } @@ -138,7 +138,7 @@ public override async Task Select_collection_FirstOrDefault_project_single_colum SELECT TOP(@__p_0) ( SELECT TOP(1) [o].[CustomerID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID]) FROM [Customers] AS [c] ORDER BY [c].[CustomerID]"); @@ -154,7 +154,7 @@ public override async Task Select_collection_FirstOrDefault_project_single_colum SELECT TOP(@__p_0) ( SELECT TOP(1) [o].[CustomerID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID]) FROM [Customers] AS [c] ORDER BY [c].[CustomerID]"); @@ -270,7 +270,7 @@ public override async Task Select_Where_Navigation_Included(bool isAsync) @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] -WHERE ([c].[City] = N'Seattle') AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = N'Seattle'"); } public override async Task Include_with_multiple_optional_navigations(bool isAsync) @@ -282,7 +282,7 @@ public override async Task Include_with_multiple_optional_navigations(bool isAsy FROM [Order Details] AS [o] INNER JOIN [Orders] AS [o0] ON [o].[OrderID] = [o0].[OrderID] LEFT JOIN [Customers] AS [c] ON [o0].[CustomerID] = [c].[CustomerID] -WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = N'London'"); } public override async Task Select_Navigation(bool isAsync) @@ -313,7 +313,7 @@ public override async Task Select_Where_Navigation_Multiple_Access(bool isAsync) @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] -WHERE (([c].[City] = N'Seattle') AND [c].[City] IS NOT NULL) AND (([c].[Phone] <> N'555 555 5555') OR [c].[Phone] IS NULL)"); +WHERE ([c].[City] = N'Seattle') AND (([c].[Phone] <> N'555 555 5555') OR [c].[Phone] IS NULL)"); } public override async Task Select_Navigations_Where_Navigations(bool isAsync) @@ -324,7 +324,7 @@ public override async Task Select_Navigations_Where_Navigations(bool isAsync) @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] -WHERE (([c].[City] = N'Seattle') AND [c].[City] IS NOT NULL) AND (([c].[Phone] <> N'555 555 5555') OR [c].[Phone] IS NULL)"); +WHERE ([c].[City] = N'Seattle') AND (([c].[Phone] <> N'555 555 5555') OR [c].[Phone] IS NULL)"); } public override async Task Select_Singleton_Navigation_With_Member_Access(bool isAsync) @@ -335,7 +335,7 @@ public override async Task Select_Singleton_Navigation_With_Member_Access(bool i @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] -WHERE (([c].[City] = N'Seattle') AND [c].[City] IS NOT NULL) AND (([c].[Phone] <> N'555 555 5555') OR [c].[Phone] IS NULL)"); +WHERE ([c].[City] = N'Seattle') AND (([c].[Phone] <> N'555 555 5555') OR [c].[Phone] IS NULL)"); } public override async Task Select_count_plus_sum(bool isAsync) @@ -361,7 +361,7 @@ public override async Task Singleton_Navigation_With_Member_Access(bool isAsync) @"SELECT [c].[City] AS [B] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] -WHERE (([c].[City] = N'Seattle') AND [c].[City] IS NOT NULL) AND (([c].[Phone] <> N'555 555 5555') OR [c].[Phone] IS NULL)"); +WHERE ([c].[City] = N'Seattle') AND (([c].[Phone] <> N'555 555 5555') OR [c].[Phone] IS NULL)"); } public override async Task Select_Where_Navigation_Scalar_Equals_Navigation_Scalar_Projected(bool isAsync) @@ -378,7 +378,7 @@ WHERE [o0].[OrderID] < 10400 ) AS [t] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] LEFT JOIN [Customers] AS [c0] ON [t].[CustomerID] = [c0].[CustomerID] -WHERE ([o].[OrderID] < 10300) AND ((([c].[City] = [c0].[City]) AND ([c].[City] IS NOT NULL AND [c0].[City] IS NOT NULL)) OR ([c].[City] IS NULL AND [c0].[City] IS NULL))"); +WHERE ([o].[OrderID] < 10300) AND (([c].[City] = [c0].[City]) OR ([c].[City] IS NULL AND [c0].[City] IS NULL))"); } public override async Task Select_Where_Navigation_Equals_Navigation(bool isAsync) @@ -391,7 +391,7 @@ FROM [Orders] AS [o] CROSS JOIN [Orders] AS [o0] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] LEFT JOIN [Customers] AS [c0] ON [o0].[CustomerID] = [c0].[CustomerID] -WHERE (([o].[CustomerID] IS NOT NULL AND ([o].[CustomerID] LIKE N'A%')) AND ([o0].[CustomerID] IS NOT NULL AND ([o0].[CustomerID] LIKE N'A%'))) AND ((([c].[CustomerID] = [c0].[CustomerID]) AND ([c].[CustomerID] IS NOT NULL AND [c0].[CustomerID] IS NOT NULL)) OR ([c].[CustomerID] IS NULL AND [c0].[CustomerID] IS NULL))"); +WHERE (([o].[CustomerID] IS NOT NULL AND ([o].[CustomerID] LIKE N'A%')) AND ([o0].[CustomerID] IS NOT NULL AND ([o0].[CustomerID] LIKE N'A%'))) AND (([c].[CustomerID] = [c0].[CustomerID]) OR ([c].[CustomerID] IS NULL AND [c0].[CustomerID] IS NULL))"); } public override async Task Select_Where_Navigation_Null(bool isAsync) @@ -448,7 +448,7 @@ public override async Task Select_collection_navigation_simple2(bool isAsync) @"SELECT [c].[CustomerID], ( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AS [Count] + WHERE [c].[CustomerID] = [o].[CustomerID]) AS [Count] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY [c].[CustomerID]"); @@ -475,7 +475,7 @@ public override async Task Select_collection_navigation_multi_part(bool isAsync) FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL +WHERE [o].[CustomerID] = N'ALFKI' ORDER BY [o].[OrderID], [o0].[OrderID]"); } @@ -489,7 +489,7 @@ FROM [Order Details] AS [o] INNER JOIN [Orders] AS [o0] ON [o].[OrderID] = [o0].[OrderID] LEFT JOIN [Customers] AS [c] ON [o0].[CustomerID] = [c].[CustomerID] LEFT JOIN [Orders] AS [o1] ON [c].[CustomerID] = [o1].[CustomerID] -WHERE (([o0].[CustomerID] = N'ALFKI') AND [o0].[CustomerID] IS NOT NULL) OR (([o0].[CustomerID] = N'ANTON') AND [o0].[CustomerID] IS NOT NULL) +WHERE ([o0].[CustomerID] = N'ALFKI') OR ([o0].[CustomerID] = N'ANTON') ORDER BY [o].[OrderID], [o].[ProductID], [o0].[OrderID], [o1].[OrderID]"); } @@ -502,7 +502,7 @@ public override async Task Collection_select_nav_prop_any(bool isAsync) WHEN EXISTS ( SELECT 1 FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) THEN CAST(1 AS bit) + WHERE [c].[CustomerID] = [o].[CustomerID]) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [Any] FROM [Customers] AS [c]"); @@ -517,7 +517,7 @@ public override async Task Collection_select_nav_prop_predicate(bool isAsync) WHEN ( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) > 0 THEN CAST(1 AS bit) + WHERE [c].[CustomerID] = [o].[CustomerID]) > 0 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END FROM [Customers] AS [c]"); @@ -533,7 +533,7 @@ FROM [Customers] AS [c] WHERE EXISTS ( SELECT 1 FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL)"); + WHERE [c].[CustomerID] = [o].[CustomerID])"); } public override async Task Collection_where_nav_prop_any_predicate(bool isAsync) @@ -546,7 +546,7 @@ FROM [Customers] AS [c] WHERE EXISTS ( SELECT 1 FROM [Orders] AS [o] - WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND ([o].[OrderID] > 0))"); + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND ([o].[OrderID] > 0))"); } public override async Task Collection_select_nav_prop_all(bool isAsync) @@ -558,7 +558,7 @@ public override async Task Collection_select_nav_prop_all(bool isAsync) WHEN NOT EXISTS ( SELECT 1 FROM [Orders] AS [o] - WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND (([o].[CustomerID] <> N'ALFKI') OR [o].[CustomerID] IS NULL)) THEN CAST(1 AS bit) + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND (([o].[CustomerID] <> N'ALFKI') OR [o].[CustomerID] IS NULL)) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [All] FROM [Customers] AS [c]"); @@ -574,7 +574,7 @@ FROM [Customers] AS [c] WHERE NOT EXISTS ( SELECT 1 FROM [Orders] AS [o] - WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND (([o].[CustomerID] <> N'ALFKI') OR [o].[CustomerID] IS NULL))"); + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND (([o].[CustomerID] <> N'ALFKI') OR [o].[CustomerID] IS NULL))"); } public override async Task Collection_select_nav_prop_count(bool isAsync) @@ -585,7 +585,7 @@ public override async Task Collection_select_nav_prop_count(bool isAsync) @"SELECT ( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AS [Count] + WHERE [c].[CustomerID] = [o].[CustomerID]) AS [Count] FROM [Customers] AS [c]"); } @@ -599,7 +599,7 @@ FROM [Customers] AS [c] WHERE ( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) > 5"); + WHERE [c].[CustomerID] = [o].[CustomerID]) > 5"); } public override async Task Collection_where_nav_prop_count_reverse(bool isAsync) @@ -612,7 +612,7 @@ FROM [Customers] AS [c] WHERE 5 < ( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL)"); + WHERE [c].[CustomerID] = [o].[CustomerID])"); } public override async Task Collection_orderby_nav_prop_count(bool isAsync) @@ -625,7 +625,7 @@ FROM [Customers] AS [c] ORDER BY ( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL), [c].[CustomerID]"); + WHERE [c].[CustomerID] = [o].[CustomerID]), [c].[CustomerID]"); } public override async Task Collection_select_nav_prop_long_count(bool isAsync) @@ -636,7 +636,7 @@ public override async Task Collection_select_nav_prop_long_count(bool isAsync) @"SELECT ( SELECT COUNT_BIG(*) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AS [C] + WHERE [c].[CustomerID] = [o].[CustomerID]) AS [C] FROM [Customers] AS [c]"); } @@ -655,7 +655,7 @@ FROM [Order Details] AS [o0] WHERE ([o3].[OrderID] = [o0].[OrderID]) AND ([o0].[UnitPrice] > 10.0)) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [any], CASE - WHEN ([o3].[CustomerID] = N'ALFKI') AND [o3].[CustomerID] IS NOT NULL THEN N'50' + WHEN [o3].[CustomerID] = N'ALFKI' THEN N'50' ELSE N'10' END AS [conditional], [o3].[OrderID] AS [scalar2], CASE WHEN NOT EXISTS ( @@ -679,7 +679,7 @@ public override async Task Collection_select_nav_prop_sum(bool isAsync) @"SELECT ( SELECT SUM([o].[OrderID]) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AS [Sum] + WHERE [c].[CustomerID] = [o].[CustomerID]) AS [Sum] FROM [Customers] AS [c]"); } @@ -701,7 +701,7 @@ FROM [Customers] AS [c] WHERE ( SELECT SUM([o].[OrderID]) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) > 1000"); + WHERE [c].[CustomerID] = [o].[CustomerID]) > 1000"); } public override async Task Collection_select_nav_prop_first_or_default(bool isAsync) @@ -752,7 +752,7 @@ public override async Task Collection_select_nav_prop_first_or_default_then_nav_ SELECT TOP(1) [c].[City] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] - WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) + WHERE [o].[CustomerID] = N'ALFKI') FROM [Customers] AS [c0] WHERE [c0].[CustomerID] LIKE N'A%'"); } @@ -780,7 +780,7 @@ public override async Task Collection_select_nav_prop_first_or_default_then_nav_ SELECT TOP(1) [c].[City] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] - WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) + WHERE [o].[CustomerID] = N'ALFKI') FROM [Customers] AS [c0] WHERE [c0].[CustomerID] LIKE N'A%'"); } @@ -794,7 +794,7 @@ public override async Task Collection_select_nav_prop_first_or_default_then_nav_ SELECT TOP(1) [c].[City] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] - WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL + WHERE [o].[CustomerID] = N'ALFKI' ORDER BY [o].[CustomerID]) FROM [Customers] AS [c0] WHERE [c0].[CustomerID] LIKE N'A%'"); @@ -902,7 +902,7 @@ SELECT COUNT(*) FROM [Order Details] AS [o0] INNER JOIN [Orders] AS [o1] ON [o0].[OrderID] = [o1].[OrderID] LEFT JOIN [Customers] AS [c0] ON [o1].[CustomerID] = [c0].[CustomerID] - WHERE (([c].[Country] = [c0].[Country]) AND ([c].[Country] IS NOT NULL AND [c0].[Country] IS NOT NULL)) OR ([c].[Country] IS NULL AND [c0].[Country] IS NULL)) > 0) AND (([o].[OrderID] = 10643) OR ([o].[OrderID] = 10692))"); + WHERE ([c].[Country] = [c0].[Country]) OR ([c].[Country] IS NULL AND [c0].[Country] IS NULL)) > 0) AND (([o].[OrderID] = 10643) OR ([o].[OrderID] = 10692))"); } public override async Task GroupBy_on_nav_prop(bool isAsync) @@ -955,7 +955,7 @@ public override async Task Project_single_scalar_value_subquery_is_properly_inli @"SELECT [c].[CustomerID], ( SELECT TOP(1) [o].[OrderID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID]) AS [OrderId] FROM [Customers] AS [c]"); } @@ -1037,7 +1037,7 @@ FROM [Orders] AS [o] WHERE ( SELECT COUNT(*) FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] IS NOT NULL AND (([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL)) AND ([o0].[OrderID] > 10260)) > 30"); + WHERE ([c].[CustomerID] IS NOT NULL AND ([c].[CustomerID] = [o0].[CustomerID])) AND ([o0].[OrderID] > 10260)) > 30"); } public override async Task Client_groupjoin_with_orderby_key_descending(bool isAsync) @@ -1336,7 +1336,7 @@ FROM [Order Details] AS [o] INNER JOIN [Orders] AS [o0] ON [o].[OrderID] = [o0].[OrderID] LEFT JOIN [Customers] AS [c] ON [o0].[CustomerID] = [c].[CustomerID] INNER JOIN [Products] AS [p] ON [o].[ProductID] = [p].[ProductID] -WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = N'London'"); } private void AssertSql(params string[] expected) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Functions.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Functions.cs index 4f1c79040c4..90ce7580a26 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Functions.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Functions.cs @@ -27,7 +27,7 @@ public override async Task String_StartsWith_Identity(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (([c].[ContactName] = N'') AND [c].[ContactName] IS NOT NULL) OR ([c].[ContactName] IS NOT NULL AND (LEFT([c].[ContactName], LEN([c].[ContactName])) = [c].[ContactName]))"); +WHERE ([c].[ContactName] = N'') OR ([c].[ContactName] IS NOT NULL AND ([c].[ContactName] IS NOT NULL AND (LEFT([c].[ContactName], LEN([c].[ContactName])) = [c].[ContactName])))"); } public override async Task String_StartsWith_Column(bool isAsync) @@ -37,7 +37,7 @@ public override async Task String_StartsWith_Column(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (([c].[ContactName] = N'') AND [c].[ContactName] IS NOT NULL) OR ([c].[ContactName] IS NOT NULL AND (LEFT([c].[ContactName], LEN([c].[ContactName])) = [c].[ContactName]))"); +WHERE ([c].[ContactName] = N'') OR ([c].[ContactName] IS NOT NULL AND ([c].[ContactName] IS NOT NULL AND (LEFT([c].[ContactName], LEN([c].[ContactName])) = [c].[ContactName])))"); } public override async Task String_StartsWith_MethodCall(bool isAsync) @@ -67,7 +67,7 @@ public override async Task String_EndsWith_Identity(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (([c].[ContactName] = N'') AND [c].[ContactName] IS NOT NULL) OR ([c].[ContactName] IS NOT NULL AND (RIGHT([c].[ContactName], LEN([c].[ContactName])) = [c].[ContactName]))"); +WHERE ([c].[ContactName] = N'') OR ([c].[ContactName] IS NOT NULL AND ([c].[ContactName] IS NOT NULL AND (RIGHT([c].[ContactName], LEN([c].[ContactName])) = [c].[ContactName])))"); } public override async Task String_EndsWith_Column(bool isAsync) @@ -77,7 +77,7 @@ public override async Task String_EndsWith_Column(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (([c].[ContactName] = N'') AND [c].[ContactName] IS NOT NULL) OR ([c].[ContactName] IS NOT NULL AND (RIGHT([c].[ContactName], LEN([c].[ContactName])) = [c].[ContactName]))"); +WHERE ([c].[ContactName] = N'') OR ([c].[ContactName] IS NOT NULL AND ([c].[ContactName] IS NOT NULL AND (RIGHT([c].[ContactName], LEN([c].[ContactName])) = [c].[ContactName])))"); } public override async Task String_EndsWith_MethodCall(bool isAsync) @@ -112,7 +112,7 @@ public override async Task String_Contains_Identity(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (([c].[ContactName] = N'') AND [c].[ContactName] IS NOT NULL) OR (CHARINDEX([c].[ContactName], [c].[ContactName]) > 0)"); +WHERE ([c].[ContactName] = N'') OR (CHARINDEX([c].[ContactName], [c].[ContactName]) > 0)"); } public override async Task String_Contains_Column(bool isAsync) @@ -122,7 +122,7 @@ public override async Task String_Contains_Column(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (([c].[ContactName] = N'') AND [c].[ContactName] IS NOT NULL) OR (CHARINDEX([c].[ContactName], [c].[ContactName]) > 0)"); +WHERE ([c].[ContactName] = N'') OR (CHARINDEX([c].[ContactName], [c].[ContactName]) > 0)"); } public override async Task String_Contains_MethodCall(bool isAsync) @@ -834,7 +834,7 @@ public override async Task Where_guid_newguid(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice] FROM [Order Details] AS [o] -WHERE NEWID() <> '00000000-0000-0000-0000-000000000000'"); +WHERE (NEWID() <> '00000000-0000-0000-0000-000000000000') OR NEWID() IS NULL"); } public override async Task Where_string_to_upper(bool isAsync) @@ -874,35 +874,35 @@ public override async Task Convert_ToByte(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(tinyint, CONVERT(tinyint, [o].[OrderID] % 1)) >= CAST(0 AS tinyint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(tinyint, CONVERT(tinyint, [o].[OrderID] % 1)) >= CAST(0 AS tinyint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(tinyint, CONVERT(decimal(18, 2), [o].[OrderID] % 1)) >= CAST(0 AS tinyint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(tinyint, CONVERT(decimal(18, 2), [o].[OrderID] % 1)) >= CAST(0 AS tinyint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(tinyint, CONVERT(float, [o].[OrderID] % 1)) >= CAST(0 AS tinyint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(tinyint, CONVERT(float, [o].[OrderID] % 1)) >= CAST(0 AS tinyint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(tinyint, CAST(CONVERT(float, [o].[OrderID] % 1) AS real)) >= CAST(0 AS tinyint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(tinyint, CAST(CONVERT(float, [o].[OrderID] % 1) AS real)) >= CAST(0 AS tinyint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(tinyint, CONVERT(smallint, [o].[OrderID] % 1)) >= CAST(0 AS tinyint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(tinyint, CONVERT(smallint, [o].[OrderID] % 1)) >= CAST(0 AS tinyint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(tinyint, CONVERT(int, [o].[OrderID] % 1)) >= CAST(0 AS tinyint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(tinyint, CONVERT(int, [o].[OrderID] % 1)) >= CAST(0 AS tinyint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(tinyint, CONVERT(bigint, [o].[OrderID] % 1)) >= CAST(0 AS tinyint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(tinyint, CONVERT(bigint, [o].[OrderID] % 1)) >= CAST(0 AS tinyint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(tinyint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS tinyint))"); +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(tinyint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS tinyint))"); } public override async Task Convert_ToDecimal(bool isAsync) @@ -912,35 +912,35 @@ public override async Task Convert_ToDecimal(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(decimal(18, 2), CONVERT(tinyint, [o].[OrderID] % 1)) >= 0.0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(decimal(18, 2), CONVERT(tinyint, [o].[OrderID] % 1)) >= 0.0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(decimal(18, 2), CONVERT(decimal(18, 2), [o].[OrderID] % 1)) >= 0.0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(decimal(18, 2), CONVERT(decimal(18, 2), [o].[OrderID] % 1)) >= 0.0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(decimal(18, 2), CONVERT(float, [o].[OrderID] % 1)) >= 0.0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(decimal(18, 2), CONVERT(float, [o].[OrderID] % 1)) >= 0.0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(decimal(18, 2), CAST(CONVERT(float, [o].[OrderID] % 1) AS real)) >= 0.0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(decimal(18, 2), CAST(CONVERT(float, [o].[OrderID] % 1) AS real)) >= 0.0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(decimal(18, 2), CONVERT(smallint, [o].[OrderID] % 1)) >= 0.0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(decimal(18, 2), CONVERT(smallint, [o].[OrderID] % 1)) >= 0.0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(decimal(18, 2), CONVERT(int, [o].[OrderID] % 1)) >= 0.0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(decimal(18, 2), CONVERT(int, [o].[OrderID] % 1)) >= 0.0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(decimal(18, 2), CONVERT(bigint, [o].[OrderID] % 1)) >= 0.0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(decimal(18, 2), CONVERT(bigint, [o].[OrderID] % 1)) >= 0.0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(decimal(18, 2), CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0.0)"); +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(decimal(18, 2), CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0.0)"); } public override async Task Convert_ToDouble(bool isAsync) @@ -950,35 +950,35 @@ public override async Task Convert_ToDouble(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(float, CONVERT(tinyint, [o].[OrderID] % 1)) >= 0.0E0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(float, CONVERT(tinyint, [o].[OrderID] % 1)) >= 0.0E0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(float, CONVERT(decimal(18, 2), [o].[OrderID] % 1)) >= 0.0E0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(float, CONVERT(decimal(18, 2), [o].[OrderID] % 1)) >= 0.0E0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(float, CONVERT(float, [o].[OrderID] % 1)) >= 0.0E0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(float, CONVERT(float, [o].[OrderID] % 1)) >= 0.0E0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(float, CAST(CONVERT(float, [o].[OrderID] % 1) AS real)) >= 0.0E0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(float, CAST(CONVERT(float, [o].[OrderID] % 1) AS real)) >= 0.0E0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(float, CONVERT(smallint, [o].[OrderID] % 1)) >= 0.0E0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(float, CONVERT(smallint, [o].[OrderID] % 1)) >= 0.0E0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(float, CONVERT(int, [o].[OrderID] % 1)) >= 0.0E0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(float, CONVERT(int, [o].[OrderID] % 1)) >= 0.0E0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(float, CONVERT(bigint, [o].[OrderID] % 1)) >= 0.0E0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(float, CONVERT(bigint, [o].[OrderID] % 1)) >= 0.0E0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(float, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0.0E0)"); +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(float, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0.0E0)"); } public override async Task Convert_ToInt16(bool isAsync) @@ -988,35 +988,35 @@ public override async Task Convert_ToInt16(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(smallint, CONVERT(tinyint, [o].[OrderID] % 1)) >= CAST(0 AS smallint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(smallint, CONVERT(tinyint, [o].[OrderID] % 1)) >= CAST(0 AS smallint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(smallint, CONVERT(decimal(18, 2), [o].[OrderID] % 1)) >= CAST(0 AS smallint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(smallint, CONVERT(decimal(18, 2), [o].[OrderID] % 1)) >= CAST(0 AS smallint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(smallint, CONVERT(float, [o].[OrderID] % 1)) >= CAST(0 AS smallint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(smallint, CONVERT(float, [o].[OrderID] % 1)) >= CAST(0 AS smallint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(smallint, CAST(CONVERT(float, [o].[OrderID] % 1) AS real)) >= CAST(0 AS smallint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(smallint, CAST(CONVERT(float, [o].[OrderID] % 1) AS real)) >= CAST(0 AS smallint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(smallint, CONVERT(smallint, [o].[OrderID] % 1)) >= CAST(0 AS smallint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(smallint, CONVERT(smallint, [o].[OrderID] % 1)) >= CAST(0 AS smallint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(smallint, CONVERT(int, [o].[OrderID] % 1)) >= CAST(0 AS smallint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(smallint, CONVERT(int, [o].[OrderID] % 1)) >= CAST(0 AS smallint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(smallint, CONVERT(bigint, [o].[OrderID] % 1)) >= CAST(0 AS smallint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(smallint, CONVERT(bigint, [o].[OrderID] % 1)) >= CAST(0 AS smallint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(smallint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS smallint))"); +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(smallint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS smallint))"); } public override async Task Convert_ToInt32(bool isAsync) @@ -1026,35 +1026,35 @@ public override async Task Convert_ToInt32(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(int, CONVERT(tinyint, [o].[OrderID] % 1)) >= 0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(int, CONVERT(tinyint, [o].[OrderID] % 1)) >= 0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(int, CONVERT(decimal(18, 2), [o].[OrderID] % 1)) >= 0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(int, CONVERT(decimal(18, 2), [o].[OrderID] % 1)) >= 0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(int, CONVERT(float, [o].[OrderID] % 1)) >= 0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(int, CONVERT(float, [o].[OrderID] % 1)) >= 0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(int, CAST(CONVERT(float, [o].[OrderID] % 1) AS real)) >= 0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(int, CAST(CONVERT(float, [o].[OrderID] % 1) AS real)) >= 0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(int, CONVERT(smallint, [o].[OrderID] % 1)) >= 0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(int, CONVERT(smallint, [o].[OrderID] % 1)) >= 0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(int, CONVERT(int, [o].[OrderID] % 1)) >= 0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(int, CONVERT(int, [o].[OrderID] % 1)) >= 0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(int, CONVERT(bigint, [o].[OrderID] % 1)) >= 0)", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(int, CONVERT(bigint, [o].[OrderID] % 1)) >= 0)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(int, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0)"); +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(int, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= 0)"); } public override async Task Convert_ToInt64(bool isAsync) @@ -1064,35 +1064,35 @@ public override async Task Convert_ToInt64(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(bigint, CONVERT(tinyint, [o].[OrderID] % 1)) >= CAST(0 AS bigint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(bigint, CONVERT(tinyint, [o].[OrderID] % 1)) >= CAST(0 AS bigint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(bigint, CONVERT(decimal(18, 2), [o].[OrderID] % 1)) >= CAST(0 AS bigint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(bigint, CONVERT(decimal(18, 2), [o].[OrderID] % 1)) >= CAST(0 AS bigint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(bigint, CONVERT(float, [o].[OrderID] % 1)) >= CAST(0 AS bigint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(bigint, CONVERT(float, [o].[OrderID] % 1)) >= CAST(0 AS bigint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(bigint, CAST(CONVERT(float, [o].[OrderID] % 1) AS real)) >= CAST(0 AS bigint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(bigint, CAST(CONVERT(float, [o].[OrderID] % 1) AS real)) >= CAST(0 AS bigint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(bigint, CONVERT(smallint, [o].[OrderID] % 1)) >= CAST(0 AS bigint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(bigint, CONVERT(smallint, [o].[OrderID] % 1)) >= CAST(0 AS bigint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(bigint, CONVERT(int, [o].[OrderID] % 1)) >= CAST(0 AS bigint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(bigint, CONVERT(int, [o].[OrderID] % 1)) >= CAST(0 AS bigint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(bigint, CONVERT(bigint, [o].[OrderID] % 1)) >= CAST(0 AS bigint))", +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(bigint, CONVERT(bigint, [o].[OrderID] % 1)) >= CAST(0 AS bigint))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(bigint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS bigint))"); +WHERE ([o].[CustomerID] = N'ALFKI') AND (CONVERT(bigint, CONVERT(nvarchar(max), [o].[OrderID] % 1)) >= CAST(0 AS bigint))"); } public override async Task Convert_ToString(bool isAsync) @@ -1102,39 +1102,39 @@ public override async Task Convert_ToString(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(nvarchar(max), CONVERT(tinyint, [o].[OrderID] % 1)) <> N'10')", +WHERE ([o].[CustomerID] = N'ALFKI') AND ((CONVERT(nvarchar(max), CONVERT(tinyint, [o].[OrderID] % 1)) <> N'10') OR CONVERT(nvarchar(max), CONVERT(tinyint, [o].[OrderID] % 1)) IS NULL)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(nvarchar(max), CONVERT(decimal(18, 2), [o].[OrderID] % 1)) <> N'10')", +WHERE ([o].[CustomerID] = N'ALFKI') AND ((CONVERT(nvarchar(max), CONVERT(decimal(18, 2), [o].[OrderID] % 1)) <> N'10') OR CONVERT(nvarchar(max), CONVERT(decimal(18, 2), [o].[OrderID] % 1)) IS NULL)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(nvarchar(max), CONVERT(float, [o].[OrderID] % 1)) <> N'10')", +WHERE ([o].[CustomerID] = N'ALFKI') AND ((CONVERT(nvarchar(max), CONVERT(float, [o].[OrderID] % 1)) <> N'10') OR CONVERT(nvarchar(max), CONVERT(float, [o].[OrderID] % 1)) IS NULL)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(nvarchar(max), CAST(CONVERT(float, [o].[OrderID] % 1) AS real)) <> N'10')", +WHERE ([o].[CustomerID] = N'ALFKI') AND ((CONVERT(nvarchar(max), CAST(CONVERT(float, [o].[OrderID] % 1) AS real)) <> N'10') OR CONVERT(nvarchar(max), CAST(CONVERT(float, [o].[OrderID] % 1) AS real)) IS NULL)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(nvarchar(max), CONVERT(smallint, [o].[OrderID] % 1)) <> N'10')", +WHERE ([o].[CustomerID] = N'ALFKI') AND ((CONVERT(nvarchar(max), CONVERT(smallint, [o].[OrderID] % 1)) <> N'10') OR CONVERT(nvarchar(max), CONVERT(smallint, [o].[OrderID] % 1)) IS NULL)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(nvarchar(max), CONVERT(int, [o].[OrderID] % 1)) <> N'10')", +WHERE ([o].[CustomerID] = N'ALFKI') AND ((CONVERT(nvarchar(max), CONVERT(int, [o].[OrderID] % 1)) <> N'10') OR CONVERT(nvarchar(max), CONVERT(int, [o].[OrderID] % 1)) IS NULL)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(nvarchar(max), CONVERT(bigint, [o].[OrderID] % 1)) <> N'10')", +WHERE ([o].[CustomerID] = N'ALFKI') AND ((CONVERT(nvarchar(max), CONVERT(bigint, [o].[OrderID] % 1)) <> N'10') OR CONVERT(nvarchar(max), CONVERT(bigint, [o].[OrderID] % 1)) IS NULL)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (CONVERT(nvarchar(max), CONVERT(nvarchar(max), [o].[OrderID] % 1)) <> N'10')", +WHERE ([o].[CustomerID] = N'ALFKI') AND ((CONVERT(nvarchar(max), CONVERT(nvarchar(max), [o].[OrderID] % 1)) <> N'10') OR CONVERT(nvarchar(max), CONVERT(nvarchar(max), [o].[OrderID] % 1)) IS NULL)", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND ((CHARINDEX(N'1997', CONVERT(nvarchar(max), [o].[OrderDate])) > 0) OR (CHARINDEX(N'1998', CONVERT(nvarchar(max), [o].[OrderDate])) > 0))"); +WHERE ([o].[CustomerID] = N'ALFKI') AND ((CHARINDEX(N'1997', CONVERT(nvarchar(max), [o].[OrderDate])) > 0) OR (CHARINDEX(N'1998', CONVERT(nvarchar(max), [o].[OrderDate])) > 0))"); } public override async Task Indexof_with_emptystring(bool isAsync) @@ -1225,7 +1225,7 @@ public override async Task IsNullOrEmpty_in_predicate(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[Region] IS NULL OR (([c].[Region] = N'') AND [c].[Region] IS NOT NULL)"); +WHERE [c].[Region] IS NULL OR ([c].[Region] = N'')"); } public override void IsNullOrEmpty_in_projection() @@ -1259,7 +1259,17 @@ public override async Task IsNullOrWhiteSpace_in_predicate(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[Region] IS NULL OR ((LTRIM(RTRIM([c].[Region])) = N'') AND LTRIM(RTRIM([c].[Region])) IS NOT NULL)"); +WHERE [c].[Region] IS NULL OR (LTRIM(RTRIM([c].[Region])) = N'')"); + } + + public override async Task IsNullOrWhiteSpace_in_predicate_on_non_nullable_column(bool isAsync) + { + await base.IsNullOrWhiteSpace_in_predicate_on_non_nullable_column(isAsync); + + AssertSql( + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c] +WHERE LTRIM(RTRIM([c].[CustomerID])) = N''"); } public override async Task TrimStart_without_arguments_in_predicate(bool isAsync) @@ -1269,7 +1279,7 @@ public override async Task TrimStart_without_arguments_in_predicate(bool isAsync AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (LTRIM([c].[ContactTitle]) = N'Owner') AND LTRIM([c].[ContactTitle]) IS NOT NULL"); +WHERE LTRIM([c].[ContactTitle]) = N'Owner'"); } [ConditionalTheory(Skip = "Issue#17328")] @@ -1287,7 +1297,7 @@ public override async Task TrimEnd_without_arguments_in_predicate(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (RTRIM([c].[ContactTitle]) = N'Owner') AND RTRIM([c].[ContactTitle]) IS NOT NULL"); +WHERE RTRIM([c].[ContactTitle]) = N'Owner'"); } [ConditionalTheory(Skip = "Issue#17328")] @@ -1305,7 +1315,7 @@ public override async Task Trim_without_argument_in_predicate(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (LTRIM(RTRIM([c].[ContactTitle])) = N'Owner') AND LTRIM(RTRIM([c].[ContactTitle])) IS NOT NULL"); +WHERE LTRIM(RTRIM([c].[ContactTitle])) = N'Owner'"); } [ConditionalTheory(Skip = "Issue#17328")] @@ -1356,7 +1366,7 @@ public override async Task Static_equals_nullable_datetime_compared_to_non_nulla SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE ([o].[OrderDate] = @__arg_0) AND [o].[OrderDate] IS NOT NULL"); +WHERE [o].[OrderDate] = @__arg_0"); } public override async Task Static_equals_int_compared_to_long(bool isAsync) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.JoinGroupJoin.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.JoinGroupJoin.cs index c2bde345052..9492ae12052 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.JoinGroupJoin.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.JoinGroupJoin.cs @@ -99,7 +99,7 @@ INNER JOIN ( SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] ) AS [t] ON [c].[CustomerID] = [t].[CustomerID] -WHERE ([t].[CustomerID] = N'ALFKI') AND [t].[CustomerID] IS NOT NULL"); +WHERE [t].[CustomerID] = N'ALFKI'"); } public override async Task Join_customers_orders_with_subquery_with_take(bool isAsync) @@ -116,7 +116,7 @@ SELECT TOP(@__p_0) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[Order FROM [Orders] AS [o] ORDER BY [o].[OrderID] ) AS [t] ON [c].[CustomerID] = [t].[CustomerID] -WHERE ([t].[CustomerID] = N'ALFKI') AND [t].[CustomerID] IS NOT NULL"); +WHERE [t].[CustomerID] = N'ALFKI'"); } public override async Task Join_customers_orders_with_subquery_anonymous_property_method(bool isAsync) @@ -130,7 +130,7 @@ INNER JOIN ( SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] ) AS [t] ON [c].[CustomerID] = [t].[CustomerID] -WHERE ([t].[CustomerID] = N'ALFKI') AND [t].[CustomerID] IS NOT NULL"); +WHERE [t].[CustomerID] = N'ALFKI'"); } public override async Task Join_customers_orders_with_subquery_anonymous_property_method_with_take(bool isAsync) @@ -147,7 +147,7 @@ SELECT TOP(@__p_0) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[Order FROM [Orders] AS [o] ORDER BY [o].[OrderID] ) AS [t] ON [c].[CustomerID] = [t].[CustomerID] -WHERE ([t].[CustomerID] = N'ALFKI') AND [t].[CustomerID] IS NOT NULL"); +WHERE [t].[CustomerID] = N'ALFKI'"); } public override async Task Join_customers_orders_with_subquery_predicate(bool isAsync) @@ -162,7 +162,7 @@ INNER JOIN ( FROM [Orders] AS [o] WHERE [o].[OrderID] > 0 ) AS [t] ON [c].[CustomerID] = [t].[CustomerID] -WHERE ([t].[CustomerID] = N'ALFKI') AND [t].[CustomerID] IS NOT NULL"); +WHERE [t].[CustomerID] = N'ALFKI'"); } public override async Task Join_customers_orders_with_subquery_predicate_with_take(bool isAsync) @@ -180,7 +180,7 @@ FROM [Orders] AS [o] WHERE [o].[OrderID] > 0 ORDER BY [o].[OrderID] ) AS [t] ON [c].[CustomerID] = [t].[CustomerID] -WHERE ([t].[CustomerID] = N'ALFKI') AND [t].[CustomerID] IS NOT NULL"); +WHERE [t].[CustomerID] = N'ALFKI'"); } public override async Task Join_composite_key(bool isAsync) @@ -190,7 +190,7 @@ public override async Task Join_composite_key(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Customers] AS [c] -INNER JOIN [Orders] AS [o] ON (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL)"); +INNER JOIN [Orders] AS [o] ON ([c].[CustomerID] = [o].[CustomerID]) AND ([c].[CustomerID] = [o].[CustomerID])"); } public override async Task Join_complex_condition(bool isAsync) @@ -405,7 +405,7 @@ public override async Task GroupJoin_Where(bool isAsync) @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Customers] AS [c] INNER JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL"); +WHERE [o].[CustomerID] = N'ALFKI'"); } public override async Task GroupJoin_Where_OrderBy(bool isAsync) @@ -416,7 +416,7 @@ public override async Task GroupJoin_Where_OrderBy(bool isAsync) @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Customers] AS [c] INNER JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) OR ([c].[CustomerID] = N'ANATR') +WHERE ([o].[CustomerID] = N'ALFKI') OR ([c].[CustomerID] = N'ANATR') ORDER BY [c].[City]"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.KeylessEntities.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.KeylessEntities.cs index 0464eeeb0f6..fc9063f7d30 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.KeylessEntities.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.KeylessEntities.cs @@ -27,7 +27,7 @@ public override async Task KeylessEntity_where_simple(bool isAsync) FROM ( SELECT [c].[CustomerID] + N'' as [CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] ) AS [c] -WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = N'London'"); } public override void KeylessEntity_by_database_view() @@ -56,12 +56,12 @@ public override void KeylessEntity_with_nav_defining_query() SELECT [c].[CompanyName], ( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AS [OrderCount], @__ef_filter___searchTerm_0 AS [SearchTerm] + WHERE [c].[CustomerID] = [o].[CustomerID]) AS [OrderCount], @__ef_filter___searchTerm_0 AS [SearchTerm] FROM [Customers] AS [c] -WHERE ((@__ef_filter___searchTerm_1 = N'') OR ([c].[CompanyName] IS NOT NULL AND ((LEFT([c].[CompanyName], LEN(@__ef_filter___searchTerm_1)) = @__ef_filter___searchTerm_1) AND LEFT([c].[CompanyName], LEN(@__ef_filter___searchTerm_1)) IS NOT NULL))) AND (( +WHERE ((@__ef_filter___searchTerm_1 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter___searchTerm_1)) = @__ef_filter___searchTerm_1))) AND (( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) > 0)"); + WHERE [c].[CustomerID] = [o].[CustomerID]) > 0)"); } public override async Task KeylessEntity_with_mixed_tracking(bool isAsync) @@ -85,7 +85,7 @@ public override async Task KeylessEntity_with_defining_query(bool isAsync) FROM ( select * from ""Orders"" ) AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL"); +WHERE [o].[CustomerID] = N'ALFKI'"); } public override async Task KeylessEntity_with_defining_query_and_correlated_collection(bool isAsync) @@ -99,7 +99,7 @@ public override async Task KeylessEntity_with_defining_query_and_correlated_coll ) AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL +WHERE [o].[CustomerID] = N'ALFKI' ORDER BY [c].[CustomerID], [o].[OrderID], [o0].[OrderID]"); } @@ -113,7 +113,7 @@ public override async Task KeylessEntity_select_where_navigation(bool isAsync) select * from ""Orders"" ) AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] -WHERE ([c].[City] = N'Seattle') AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = N'Seattle'"); } public override async Task KeylessEntity_select_where_navigation_multi_level(bool isAsync) @@ -129,7 +129,7 @@ public override async Task KeylessEntity_select_where_navigation_multi_level(boo WHERE EXISTS ( SELECT 1 FROM [Orders] AS [o0] - WHERE [c].[CustomerID] IS NOT NULL AND (([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL))"); + WHERE [c].[CustomerID] IS NOT NULL AND ([c].[CustomerID] = [o0].[CustomerID]))"); } [ConditionalFact] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.ResultOperators.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.ResultOperators.cs index f3278cc7378..1041108f52c 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.ResultOperators.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.ResultOperators.cs @@ -414,7 +414,7 @@ public override async Task Count_with_predicate(bool isAsync) AssertSql( @"SELECT COUNT(*) FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL"); +WHERE [o].[CustomerID] = N'ALFKI'"); } public override async Task Where_OrderBy_Count(bool isAsync) @@ -424,7 +424,7 @@ public override async Task Where_OrderBy_Count(bool isAsync) AssertSql( @"SELECT COUNT(*) FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL"); +WHERE [o].[CustomerID] = N'ALFKI'"); } public override async Task OrderBy_Where_Count(bool isAsync) @@ -434,7 +434,7 @@ public override async Task OrderBy_Where_Count(bool isAsync) AssertSql( @"SELECT COUNT(*) FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL"); +WHERE [o].[CustomerID] = N'ALFKI'"); } public override async Task OrderBy_Count_with_predicate(bool isAsync) @@ -444,7 +444,7 @@ public override async Task OrderBy_Count_with_predicate(bool isAsync) AssertSql( @"SELECT COUNT(*) FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL"); +WHERE [o].[CustomerID] = N'ALFKI'"); } public override async Task OrderBy_Where_Count_with_predicate(bool isAsync) @@ -635,13 +635,10 @@ public override async Task First_inside_subquery_gets_client_evaluated(bool isAs AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[CustomerID] = N'ALFKI') AND ((( +WHERE ([c].[CustomerID] = N'ALFKI') AND (( SELECT TOP(1) [o].[CustomerID] FROM [Orders] AS [o] - WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL)) = N'ALFKI') AND ( - SELECT TOP(1) [o].[CustomerID] - FROM [Orders] AS [o] - WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL)) IS NOT NULL)"); + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND ([o].[CustomerID] = N'ALFKI')) = N'ALFKI')"); } public override async Task Last(bool isAsync) @@ -661,7 +658,7 @@ public override async Task Last_Predicate(bool isAsync) AssertSql( @"SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL +WHERE [c].[City] = N'London' ORDER BY [c].[ContactName] DESC"); } @@ -672,7 +669,7 @@ public override async Task Where_Last(bool isAsync) AssertSql( @"SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL +WHERE [c].[City] = N'London' ORDER BY [c].[ContactName] DESC"); } @@ -693,7 +690,7 @@ public override async Task LastOrDefault_Predicate(bool isAsync) AssertSql( @"SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL +WHERE [c].[City] = N'London' ORDER BY [c].[ContactName] DESC"); } @@ -704,7 +701,7 @@ public override async Task Where_LastOrDefault(bool isAsync) AssertSql( @"SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL +WHERE [c].[City] = N'London' ORDER BY [c].[ContactName] DESC"); } @@ -1084,7 +1081,7 @@ SELECT CASE WHEN @__entity_equality_p_0_OrderID IN ( SELECT [o].[OrderID] FROM [Orders] AS [o] - WHERE ([o].[CustomerID] = N'VINET') AND [o].[CustomerID] IS NOT NULL + WHERE [o].[CustomerID] = N'VINET' ) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) @@ -1103,7 +1100,7 @@ FROM [Customers] AS [c] WHERE @__entity_equality_someOrder_0_OrderID IN ( SELECT [o].[OrderID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] )"); } @@ -1178,7 +1175,7 @@ SELECT CASE WHEN @__entity_equality_p_0_OrderID IN ( SELECT [o].[OrderID] FROM [Orders] AS [o] - WHERE ([o].[CustomerID] = N'VINET') AND [o].[CustomerID] IS NOT NULL + WHERE [o].[CustomerID] = N'VINET' ) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) @@ -1240,11 +1237,11 @@ public override async Task Where_subquery_where_any(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (([c].[City] = N'México D.F.') AND [c].[City] IS NOT NULL) AND [c].[CustomerID] IN (N'ABCDE', N'ALFKI', N'ANATR')", +WHERE ([c].[City] = N'México D.F.') AND [c].[CustomerID] IN (N'ABCDE', N'ALFKI', N'ANATR')", // @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (([c].[City] = N'México D.F.') AND [c].[City] IS NOT NULL) AND [c].[CustomerID] IN (N'ABCDE', N'ALFKI', N'ANATR')"); +WHERE ([c].[City] = N'México D.F.') AND [c].[CustomerID] IN (N'ABCDE', N'ALFKI', N'ANATR')"); } public override async Task Where_subquery_all_not_equals_operator(bool isAsync) @@ -1284,11 +1281,11 @@ public override async Task Where_subquery_where_all(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (([c].[City] = N'México D.F.') AND [c].[City] IS NOT NULL) AND [c].[CustomerID] NOT IN (N'ABCDE', N'ALFKI', N'ANATR')", +WHERE ([c].[City] = N'México D.F.') AND [c].[CustomerID] NOT IN (N'ABCDE', N'ALFKI', N'ANATR')", // @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (([c].[City] = N'México D.F.') AND [c].[City] IS NOT NULL) AND [c].[CustomerID] NOT IN (N'ABCDE', N'ALFKI', N'ANATR')"); +WHERE ([c].[City] = N'México D.F.') AND [c].[CustomerID] NOT IN (N'ABCDE', N'ALFKI', N'ANATR')"); } public override async Task Cast_to_same_Type_Count_works(bool isAsync) @@ -1308,7 +1305,7 @@ public override async Task Cast_before_aggregate_is_preserved(bool isAsync) @"SELECT ( SELECT AVG(CAST([o].[OrderID] AS float)) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) + WHERE [c].[CustomerID] = [o].[CustomerID]) FROM [Customers] AS [c]"); } @@ -1331,15 +1328,11 @@ public override async Task Collection_Last_member_access_in_projection_translate AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[CustomerID] LIKE N'F%') AND ((( - SELECT TOP(1) [o].[CustomerID] - FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL - ORDER BY [o].[OrderID]) = [c].[CustomerID]) AND ( +WHERE ([c].[CustomerID] LIKE N'F%') AND (( SELECT TOP(1) [o].[CustomerID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL - ORDER BY [o].[OrderID]) IS NOT NULL)"); + WHERE [c].[CustomerID] = [o].[CustomerID] + ORDER BY [o].[OrderID]) = [c].[CustomerID])"); } public override async Task Collection_LastOrDefault_member_access_in_projection_translated(bool isAsync) @@ -1349,15 +1342,11 @@ public override async Task Collection_LastOrDefault_member_access_in_projection_ AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[CustomerID] LIKE N'F%') AND ((( - SELECT TOP(1) [o].[CustomerID] - FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL - ORDER BY [o].[OrderID]) = [c].[CustomerID]) AND ( +WHERE ([c].[CustomerID] LIKE N'F%') AND (( SELECT TOP(1) [o].[CustomerID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL - ORDER BY [o].[OrderID]) IS NOT NULL)"); + WHERE [c].[CustomerID] = [o].[CustomerID] + ORDER BY [o].[OrderID]) = [c].[CustomerID])"); } public override async Task Sum_over_explicit_cast_over_column(bool isAsync) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Select.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Select.cs index 0cfb54d3137..448d957833e 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Select.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Select.cs @@ -242,7 +242,7 @@ public override async Task Select_project_filter(bool isAsync) AssertSql( @"SELECT [c].[CompanyName] FROM [Customers] AS [c] -WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = N'London'"); } public override async Task Select_project_filter2(bool isAsync) @@ -252,7 +252,7 @@ public override async Task Select_project_filter2(bool isAsync) AssertSql( @"SELECT [c].[City] FROM [Customers] AS [c] -WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = N'London'"); } public override async Task Select_nested_collection(bool isAsync) @@ -318,7 +318,7 @@ FROM [Customers] AS [c] OUTER APPLY ( SELECT TOP(3) [o].[OrderDate], [o].[OrderID] FROM [Orders] AS [o] - WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND ([o].[OrderID] < 10500) + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND ([o].[OrderID] < 10500) ) AS [t] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY [c].[CustomerID], [t].[OrderID]"); @@ -332,7 +332,7 @@ public override void Select_nested_collection_multi_level2() @"SELECT ( SELECT TOP(1) [o].[OrderDate] FROM [Orders] AS [o] - WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND ([o].[OrderID] < 10500)) AS [OrderDates] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND ([o].[OrderID] < 10500)) AS [OrderDates] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%'"); } @@ -345,7 +345,7 @@ public override void Select_nested_collection_multi_level3() @"SELECT ( SELECT TOP(1) [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([o].[OrderID] < 10500) AND (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL)) AS [OrderDates] + WHERE ([o].[OrderID] < 10500) AND ([c].[CustomerID] = [o].[CustomerID])) AS [OrderDates] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%'"); } @@ -361,7 +361,7 @@ SELECT COUNT(*) FROM [Order Details] AS [o] WHERE ([o0].[OrderID] = [o].[OrderID]) AND ([o].[OrderID] > 10)) FROM [Orders] AS [o0] - WHERE (([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL) AND ([o0].[OrderID] < 10500)) AS [Order] + WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND ([o0].[OrderID] < 10500)) AS [Order] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%'"); } @@ -378,12 +378,12 @@ FROM [Order Details] AS [o] WHERE ([o1].[OrderID] = [o].[OrderID]) AND (([o].[OrderID] <> ( SELECT COUNT(*) FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL)) OR ( + WHERE [c].[CustomerID] = [o0].[CustomerID])) OR ( SELECT COUNT(*) FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL) IS NULL)) + WHERE [c].[CustomerID] = [o0].[CustomerID]) IS NULL)) FROM [Orders] AS [o1] - WHERE (([c].[CustomerID] = [o1].[CustomerID]) AND [o1].[CustomerID] IS NOT NULL) AND ([o1].[OrderID] < 10500)) AS [Order] + WHERE ([c].[CustomerID] = [o1].[CustomerID]) AND ([o1].[OrderID] < 10500)) AS [Order] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%'"); } @@ -397,9 +397,9 @@ public override void Select_nested_collection_multi_level6() SELECT TOP(1) ( SELECT TOP(1) [o].[ProductID] FROM [Order Details] AS [o] - WHERE ([o0].[OrderID] = [o].[OrderID]) AND ([o].[OrderID] <> CAST(LEN([c].[CustomerID]) AS int))) + WHERE ([o0].[OrderID] = [o].[OrderID]) AND (([o].[OrderID] <> CAST(LEN([c].[CustomerID]) AS int)) OR LEN([c].[CustomerID]) IS NULL)) FROM [Orders] AS [o0] - WHERE (([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL) AND ([o0].[OrderID] < 10500)) AS [Order] + WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND ([o0].[OrderID] < 10500)) AS [Order] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%'"); } @@ -412,7 +412,7 @@ public override async Task Select_nested_collection_count_using_anonymous_type(b @"SELECT ( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AS [Count] + WHERE [c].[CustomerID] = [o].[CustomerID]) AS [Count] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%'"); } @@ -434,7 +434,7 @@ public override async Task Select_non_matching_value_types_int_to_long_introduce AssertSql( @"SELECT CAST([o].[OrderID] AS bigint) FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL +WHERE [o].[CustomerID] = N'ALFKI' ORDER BY [o].[OrderID]"); } @@ -445,7 +445,7 @@ public override async Task Select_non_matching_value_types_nullable_int_to_long_ AssertSql( @"SELECT CAST([o].[EmployeeID] AS bigint) FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL +WHERE [o].[CustomerID] = N'ALFKI' ORDER BY [o].[OrderID]"); } @@ -456,7 +456,7 @@ public override async Task Select_non_matching_value_types_nullable_int_to_int_d AssertSql( @"SELECT [o].[EmployeeID] FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL +WHERE [o].[CustomerID] = N'ALFKI' ORDER BY [o].[OrderID]"); } @@ -467,7 +467,7 @@ public override async Task Select_non_matching_value_types_int_to_nullable_int_d AssertSql( @"SELECT [o].[OrderID] FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL +WHERE [o].[CustomerID] = N'ALFKI' ORDER BY [o].[OrderID]"); } @@ -478,7 +478,7 @@ public override async Task Select_non_matching_value_types_from_binary_expressio AssertSql( @"SELECT CAST(([o].[OrderID] + [o].[OrderID]) AS bigint) FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL +WHERE [o].[CustomerID] = N'ALFKI' ORDER BY [o].[OrderID]"); } @@ -490,7 +490,7 @@ public override async Task Select_non_matching_value_types_from_binary_expressio AssertSql( @"SELECT CAST((CAST([o].[OrderID] AS bigint) + CAST([o].[OrderID] AS bigint)) AS smallint) FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL +WHERE [o].[CustomerID] = N'ALFKI' ORDER BY [o].[OrderID]"); } @@ -501,7 +501,7 @@ public override async Task Select_non_matching_value_types_from_unary_expression AssertSql( @"SELECT CAST(-[o].[OrderID] AS bigint) FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL +WHERE [o].[CustomerID] = N'ALFKI' ORDER BY [o].[OrderID]"); } @@ -512,7 +512,7 @@ public override async Task Select_non_matching_value_types_from_unary_expression AssertSql( @"SELECT -CAST([o].[OrderID] AS bigint) FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL +WHERE [o].[CustomerID] = N'ALFKI' ORDER BY [o].[OrderID]"); } @@ -523,7 +523,7 @@ public override async Task Select_non_matching_value_types_from_length_introduce AssertSql( @"SELECT CAST(CAST(LEN([o].[CustomerID]) AS int) AS bigint) FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL +WHERE [o].[CustomerID] = N'ALFKI' ORDER BY [o].[OrderID]"); } @@ -534,7 +534,7 @@ public override async Task Select_non_matching_value_types_from_method_call_intr AssertSql( @"SELECT CAST(ABS([o].[OrderID]) AS bigint) FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL +WHERE [o].[CustomerID] = N'ALFKI' ORDER BY [o].[OrderID]"); } @@ -545,7 +545,7 @@ public override async Task Select_non_matching_value_types_from_anonymous_type_i AssertSql( @"SELECT CAST([o].[OrderID] AS bigint) AS [LongOrder], CAST([o].[OrderID] AS smallint) AS [ShortOrder], [o].[OrderID] AS [Order] FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL +WHERE [o].[CustomerID] = N'ALFKI' ORDER BY [o].[OrderID]"); } @@ -562,7 +562,7 @@ ELSE CAST(0 AS bit) END END FROM [Orders] AS [o] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL"); +WHERE [o].[CustomerID] = N'ALFKI'"); } public override async Task Projection_in_a_subquery_should_be_liftable(bool isAsync) @@ -598,7 +598,7 @@ SELECT TOP(1) [t].[CustomerID] FROM ( SELECT TOP(1) [o].[CustomerID], [o].[OrderID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID] ) AS [t] ORDER BY [t].[OrderID]) @@ -613,7 +613,7 @@ public override async Task Project_single_element_from_collection_with_OrderBy_S @"SELECT ( SELECT [o].[CustomerID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID] OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY) FROM [Customers] AS [c]"); @@ -627,7 +627,7 @@ public override async Task Project_single_element_from_collection_with_OrderBy_D @"SELECT ( SELECT DISTINCT TOP(1) [o].[CustomerID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) + WHERE [c].[CustomerID] = [o].[CustomerID]) FROM [Customers] AS [c]"); } @@ -643,7 +643,7 @@ SELECT TOP(1) CAST(LEN([t].[CustomerID]) AS int) FROM ( SELECT DISTINCT [o].[CustomerID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ) AS [t]) FROM [Customers] AS [c]"); } @@ -658,7 +658,7 @@ SELECT TOP(1) [t].[CustomerID] FROM ( SELECT TOP(1) [o].[CustomerID], [o].[OrderID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID] ) AS [t] ORDER BY [t].[OrderID]) @@ -678,7 +678,7 @@ SELECT TOP(1) [t].[CustomerID] FROM ( SELECT TOP(@__i_0) [o].[CustomerID], [o].[OrderID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID] ) AS [t] ORDER BY [t].[OrderID]) @@ -695,7 +695,7 @@ SELECT TOP(1) [t].[CustomerID] FROM ( SELECT TOP(2) [o].[CustomerID], [o].[OrderID], [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID], [o].[OrderDate] DESC ) AS [t] ORDER BY [t].[OrderID], [t].[OrderDate] DESC) @@ -724,7 +724,7 @@ SELECT TOP(1) [t].[CustomerID] FROM ( SELECT TOP(2) [o].[CustomerID], [o].[OrderID], [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[CustomerID], [o].[OrderDate] DESC ) AS [t] ORDER BY [t].[CustomerID], [t].[OrderDate] DESC) @@ -992,7 +992,7 @@ FROM [Customers] AS [c] CROSS APPLY ( SELECT [c].[City], [o].[OrderID], [o].[CustomerID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ) AS [t]"); } @@ -1006,7 +1006,7 @@ FROM [Customers] AS [c] CROSS APPLY ( SELECT TOP(2) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c].[City] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [c].[City], [o].[OrderID] ) AS [t]"); } @@ -1021,7 +1021,7 @@ FROM [Customers] AS [c] OUTER APPLY ( SELECT [c].[City], [o].[OrderID], [o].[CustomerID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ) AS [t]"); } @@ -1035,7 +1035,7 @@ FROM [Customers] AS [c] OUTER APPLY ( SELECT TOP(2) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c].[City] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [c].[City], [o].[OrderID] ) AS [t]"); } @@ -1048,7 +1048,7 @@ public override async Task FirstOrDefault_over_empty_collection_of_value_type_re @"SELECT [c].[CustomerID], ( SELECT TOP(1) [o].[OrderID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID]) AS [OrderId] FROM [Customers] AS [c] WHERE [c].[CustomerID] = N'FISSA'"); @@ -1102,7 +1102,7 @@ FROM [Customers] AS [c] CROSS APPLY ( SELECT [o].[CustomerID], [c].[CustomerID] AS [CustomerID0], [o].[OrderID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ) AS [t]"); } @@ -1154,7 +1154,7 @@ ELSE CAST(0 AS bit) END FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] -WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL"); +WHERE [o].[CustomerID] = N'ALFKI'"); } public override async Task Explicit_cast_in_arithmatic_operation_is_preserved(bool isAsync) @@ -1177,7 +1177,7 @@ FROM [Customers] AS [c] CROSS APPLY ( SELECT [o].[OrderDate], [c].[City], [o].[OrderID], [o].[CustomerID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ) AS [t]"); } @@ -1196,7 +1196,7 @@ public override async Task Collection_FirstOrDefault_with_nullable_unsigned_int_ @"SELECT ( SELECT TOP(1) [o].[EmployeeID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID]) FROM [Customers] AS [c]"); } @@ -1209,7 +1209,7 @@ public override async Task ToList_Count_in_projection_works(bool isAsync) @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], ( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AS [Count] + WHERE [c].[CustomerID] = [o].[CustomerID]) AS [Count] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%'"); } @@ -1222,7 +1222,7 @@ public override async Task LastOrDefault_member_access_in_projection_translates_ @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], ( SELECT TOP(1) [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID]) AS [OrderDate] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%'"); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.SetOperations.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.SetOperations.cs index d524a32fd33..41729bd1aaa 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.SetOperations.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.SetOperations.cs @@ -16,11 +16,11 @@ public override async Task Union(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL +WHERE [c].[City] = N'Berlin' UNION SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] -WHERE ([c0].[City] = N'London') AND [c0].[City] IS NOT NULL"); +WHERE [c0].[City] = N'London'"); } public override async Task Concat(bool isAsync) @@ -30,11 +30,11 @@ public override async Task Concat(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL +WHERE [c].[City] = N'Berlin' UNION ALL SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] -WHERE ([c0].[City] = N'London') AND [c0].[City] IS NOT NULL"); +WHERE [c0].[City] = N'London'"); } public override async Task Intersect(bool isAsync) @@ -44,7 +44,7 @@ public override async Task Intersect(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL +WHERE [c].[City] = N'London' INTERSECT SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] @@ -58,7 +58,7 @@ public override async Task Except(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL +WHERE [c].[City] = N'London' EXCEPT SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] @@ -76,11 +76,11 @@ public override async Task Union_OrderBy_Skip_Take(bool isAsync) FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] - WHERE ([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL + WHERE [c].[City] = N'Berlin' UNION SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] - WHERE ([c0].[City] = N'London') AND [c0].[City] IS NOT NULL + WHERE [c0].[City] = N'London' ) AS [t] ORDER BY [t].[ContactName] OFFSET @__p_0 ROWS FETCH NEXT @__p_0 ROWS ONLY"); @@ -95,11 +95,11 @@ public override async Task Union_Where(bool isAsync) FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] - WHERE ([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL + WHERE [c].[City] = N'Berlin' UNION SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] - WHERE ([c0].[City] = N'London') AND [c0].[City] IS NOT NULL + WHERE [c0].[City] = N'London' ) AS [t] WHERE CHARINDEX(N'Thomas', [t].[ContactName]) > 0"); } @@ -117,11 +117,11 @@ public override async Task Union_Skip_Take_OrderBy_ThenBy_Where(bool isAsync) FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] - WHERE ([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL + WHERE [c].[City] = N'Berlin' UNION SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] - WHERE ([c0].[City] = N'London') AND [c0].[City] IS NOT NULL + WHERE [c0].[City] = N'London' ) AS [t] ORDER BY [t].[Region], [t].[City] OFFSET @__p_0 ROWS @@ -137,15 +137,15 @@ public override async Task Union_Union(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL +WHERE [c].[City] = N'Berlin' UNION SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] -WHERE ([c0].[City] = N'London') AND [c0].[City] IS NOT NULL +WHERE [c0].[City] = N'London' UNION SELECT [c1].[CustomerID], [c1].[Address], [c1].[City], [c1].[CompanyName], [c1].[ContactName], [c1].[ContactTitle], [c1].[Country], [c1].[Fax], [c1].[Phone], [c1].[PostalCode], [c1].[Region] FROM [Customers] AS [c1] -WHERE ([c1].[City] = N'Mannheim') AND [c1].[City] IS NOT NULL"); +WHERE [c1].[City] = N'Mannheim'"); } public override async Task Union_Intersect(bool isAsync) @@ -156,11 +156,11 @@ public override async Task Union_Intersect(bool isAsync) @"( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] - WHERE ([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL + WHERE [c].[City] = N'Berlin' UNION SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] - WHERE ([c0].[City] = N'London') AND [c0].[City] IS NOT NULL + WHERE [c0].[City] = N'London' ) INTERSECT SELECT [c1].[CustomerID], [c1].[Address], [c1].[City], [c1].[CompanyName], [c1].[ContactName], [c1].[ContactTitle], [c1].[Country], [c1].[Fax], [c1].[Phone], [c1].[PostalCode], [c1].[Region] @@ -186,18 +186,18 @@ SELECT TOP(@__p_0) [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] - WHERE ([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL + WHERE [c].[City] = N'Berlin' UNION SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] - WHERE ([c0].[City] = N'London') AND [c0].[City] IS NOT NULL + WHERE [c0].[City] = N'London' ) AS [t] ORDER BY [t].[CustomerID] ) AS [t0] UNION SELECT [c1].[CustomerID], [c1].[Address], [c1].[City], [c1].[CompanyName], [c1].[ContactName], [c1].[ContactTitle], [c1].[Country], [c1].[Fax], [c1].[Phone], [c1].[PostalCode], [c1].[Region] FROM [Customers] AS [c1] - WHERE ([c1].[City] = N'Mannheim') AND [c1].[City] IS NOT NULL + WHERE [c1].[City] = N'Mannheim' ) AS [t1] ) AS [t2] ORDER BY [t2].[CustomerID]"); @@ -210,11 +210,11 @@ public override async Task Select_Union(bool isAsync) AssertSql( @"SELECT [c].[Address] FROM [Customers] AS [c] -WHERE ([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL +WHERE [c].[City] = N'Berlin' UNION SELECT [c0].[Address] FROM [Customers] AS [c0] -WHERE ([c0].[City] = N'London') AND [c0].[City] IS NOT NULL"); +WHERE [c0].[City] = N'London'"); } public override async Task Union_Select(bool isAsync) @@ -226,11 +226,11 @@ public override async Task Union_Select(bool isAsync) FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] - WHERE ([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL + WHERE [c].[City] = N'Berlin' UNION SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] - WHERE ([c0].[City] = N'London') AND [c0].[City] IS NOT NULL + WHERE [c0].[City] = N'London' ) AS [t] WHERE CHARINDEX(N'Hanover', [t].[Address]) > 0"); } @@ -298,16 +298,16 @@ public override async Task Select_Union_different_fields_in_anonymous_with_subqu FROM ( SELECT [c].[City] AS [Foo], [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] - WHERE ([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL + WHERE [c].[City] = N'Berlin' UNION SELECT [c0].[Region] AS [Foo], [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] - WHERE ([c0].[City] = N'London') AND [c0].[City] IS NOT NULL + WHERE [c0].[City] = N'London' ) AS [t] ORDER BY [t].[Foo] OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY ) AS [t0] -WHERE ([t0].[Foo] = N'Berlin') AND [t0].[Foo] IS NOT NULL +WHERE [t0].[Foo] = N'Berlin' ORDER BY [t0].[Foo]"); } @@ -320,11 +320,11 @@ public override async Task Union_Include(bool isAsync) FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] - WHERE ([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL + WHERE [c].[City] = N'Berlin' UNION SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] - WHERE ([c0].[City] = N'London') AND [c0].[City] IS NOT NULL + WHERE [c0].[City] = N'London' ) AS [t] LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[CustomerID], [o].[OrderID]"); @@ -339,11 +339,11 @@ public override async Task Include_Union(bool isAsync) FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] - WHERE ([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL + WHERE [c].[City] = N'Berlin' UNION SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Customers] AS [c0] - WHERE ([c0].[City] = N'London') AND [c0].[City] IS NOT NULL + WHERE [c0].[City] = N'London' ) AS [t] LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[CustomerID], [o].[OrderID]"); @@ -361,7 +361,7 @@ FROM [Orders] AS [o] SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM [Orders] AS [o0] LEFT JOIN [Customers] AS [c0] ON [o0].[CustomerID] = [c0].[CustomerID] -WHERE ([o0].[CustomerID] = N'ALFKI') AND [o0].[CustomerID] IS NOT NULL"); +WHERE [o0].[CustomerID] = N'ALFKI'"); } public override async Task SubSelect_Union(bool isAsync) @@ -372,13 +372,13 @@ public override async Task SubSelect_Union(bool isAsync) @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], ( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AS [Orders] + WHERE [c].[CustomerID] = [o].[CustomerID]) AS [Orders] FROM [Customers] AS [c] UNION SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], ( SELECT COUNT(*) FROM [Orders] AS [o0] - WHERE ([c0].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL) AS [Orders] + WHERE [c0].[CustomerID] = [o0].[CustomerID]) AS [Orders] FROM [Customers] AS [c0]"); } @@ -389,12 +389,12 @@ public override async Task GroupBy_Select_Union(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], COUNT(*) AS [Count] FROM [Customers] AS [c] -WHERE ([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL +WHERE [c].[City] = N'Berlin' GROUP BY [c].[CustomerID] UNION SELECT [c0].[CustomerID], COUNT(*) AS [Count] FROM [Customers] AS [c0] -WHERE ([c0].[City] = N'London') AND [c0].[City] IS NOT NULL +WHERE [c0].[City] = N'London' GROUP BY [c0].[CustomerID]"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Where.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Where.cs index cfd5df80d24..263bc97b6c6 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Where.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Where.cs @@ -14,7 +14,7 @@ public override async Task Where_simple(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = N'London'"); } public override async Task Where_as_queryable_expression(bool isAsync) @@ -27,7 +27,7 @@ FROM [Customers] AS [c] WHERE EXISTS ( SELECT 1 FROM [Orders] AS [o] - WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL))"); + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND ([o].[CustomerID] = N'ALFKI'))"); } public override async Task Where_simple_closure(bool isAsync) @@ -39,7 +39,7 @@ public override async Task Where_simple_closure(bool isAsync) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__city_0) AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = @__city_0"); } public override async Task Where_indexer_closure(bool isAsync) @@ -51,7 +51,7 @@ public override async Task Where_indexer_closure(bool isAsync) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__p_0) AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = @__p_0"); } public override async Task Where_dictionary_key_access_closure(bool isAsync) @@ -63,7 +63,7 @@ public override async Task Where_dictionary_key_access_closure(bool isAsync) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__get_Item_0) AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = @__get_Item_0"); } public override async Task Where_tuple_item_closure(bool isAsync) @@ -75,7 +75,7 @@ public override async Task Where_tuple_item_closure(bool isAsync) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__predicateTuple_Item2_0) AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = @__predicateTuple_Item2_0"); } public override async Task Where_named_tuple_item_closure(bool isAsync) @@ -87,7 +87,7 @@ public override async Task Where_named_tuple_item_closure(bool isAsync) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__predicateTuple_Item2_0) AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = @__predicateTuple_Item2_0"); } public override async Task Where_simple_closure_constant(bool isAsync) @@ -111,13 +111,13 @@ public override async Task Where_simple_closure_via_query_cache(bool isAsync) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__city_0) AND [c].[City] IS NOT NULL", +WHERE [c].[City] = @__city_0", // @"@__city_0='Seattle' (Size = 4000) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__city_0) AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = @__city_0"); } public override async Task Where_method_call_nullable_type_closure_via_query_cache(bool isAsync) @@ -129,13 +129,13 @@ public override async Task Where_method_call_nullable_type_closure_via_query_cac SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (CAST([e].[ReportsTo] AS bigint) = @__p_0) AND [e].[ReportsTo] IS NOT NULL", +WHERE CAST([e].[ReportsTo] AS bigint) = @__p_0", // @"@__p_0='5' (Nullable = true) SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (CAST([e].[ReportsTo] AS bigint) = @__p_0) AND [e].[ReportsTo] IS NOT NULL"); +WHERE CAST([e].[ReportsTo] AS bigint) = @__p_0"); } public override async Task Where_method_call_nullable_type_reverse_closure_via_query_cache(bool isAsync) @@ -165,13 +165,13 @@ public override async Task Where_method_call_closure_via_query_cache(bool isAsyn SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__GetCity_0) AND [c].[City] IS NOT NULL", +WHERE [c].[City] = @__GetCity_0", // @"@__GetCity_0='Seattle' (Size = 4000) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__GetCity_0) AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = @__GetCity_0"); } public override async Task Where_field_access_closure_via_query_cache(bool isAsync) @@ -183,13 +183,13 @@ public override async Task Where_field_access_closure_via_query_cache(bool isAsy SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__city_InstanceFieldValue_0) AND [c].[City] IS NOT NULL", +WHERE [c].[City] = @__city_InstanceFieldValue_0", // @"@__city_InstanceFieldValue_0='Seattle' (Size = 4000) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__city_InstanceFieldValue_0) AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = @__city_InstanceFieldValue_0"); } public override async Task Where_property_access_closure_via_query_cache(bool isAsync) @@ -201,13 +201,13 @@ public override async Task Where_property_access_closure_via_query_cache(bool is SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__city_InstancePropertyValue_0) AND [c].[City] IS NOT NULL", +WHERE [c].[City] = @__city_InstancePropertyValue_0", // @"@__city_InstancePropertyValue_0='Seattle' (Size = 4000) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__city_InstancePropertyValue_0) AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = @__city_InstancePropertyValue_0"); } public override async Task Where_static_field_access_closure_via_query_cache(bool isAsync) @@ -219,13 +219,13 @@ public override async Task Where_static_field_access_closure_via_query_cache(boo SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__StaticFieldValue_0) AND [c].[City] IS NOT NULL", +WHERE [c].[City] = @__StaticFieldValue_0", // @"@__StaticFieldValue_0='Seattle' (Size = 4000) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__StaticFieldValue_0) AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = @__StaticFieldValue_0"); } public override async Task Where_static_property_access_closure_via_query_cache(bool isAsync) @@ -237,13 +237,13 @@ public override async Task Where_static_property_access_closure_via_query_cache( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__StaticPropertyValue_0) AND [c].[City] IS NOT NULL", +WHERE [c].[City] = @__StaticPropertyValue_0", // @"@__StaticPropertyValue_0='Seattle' (Size = 4000) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__StaticPropertyValue_0) AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = @__StaticPropertyValue_0"); } public override async Task Where_nested_field_access_closure_via_query_cache(bool isAsync) @@ -255,13 +255,13 @@ public override async Task Where_nested_field_access_closure_via_query_cache(boo SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__city_Nested_InstanceFieldValue_0) AND [c].[City] IS NOT NULL", +WHERE [c].[City] = @__city_Nested_InstanceFieldValue_0", // @"@__city_Nested_InstanceFieldValue_0='Seattle' (Size = 4000) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__city_Nested_InstanceFieldValue_0) AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = @__city_Nested_InstanceFieldValue_0"); } public override async Task Where_nested_property_access_closure_via_query_cache(bool isAsync) @@ -273,13 +273,13 @@ public override async Task Where_nested_property_access_closure_via_query_cache( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__city_Nested_InstancePropertyValue_0) AND [c].[City] IS NOT NULL", +WHERE [c].[City] = @__city_Nested_InstancePropertyValue_0", // @"@__city_Nested_InstancePropertyValue_0='Seattle' (Size = 4000) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__city_Nested_InstancePropertyValue_0) AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = @__city_Nested_InstancePropertyValue_0"); } public override async Task Where_new_instance_field_access_query_cache(bool isAsync) @@ -291,13 +291,13 @@ public override async Task Where_new_instance_field_access_query_cache(bool isAs SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__InstanceFieldValue_0) AND [c].[City] IS NOT NULL", +WHERE [c].[City] = @__InstanceFieldValue_0", // @"@__InstanceFieldValue_0='Seattle' (Size = 4000) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__InstanceFieldValue_0) AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = @__InstanceFieldValue_0"); } public override async Task Where_new_instance_field_access_closure_via_query_cache(bool isAsync) @@ -309,13 +309,13 @@ public override async Task Where_new_instance_field_access_closure_via_query_cac SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__InstanceFieldValue_0) AND [c].[City] IS NOT NULL", +WHERE [c].[City] = @__InstanceFieldValue_0", // @"@__InstanceFieldValue_0='Seattle' (Size = 4000) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = @__InstanceFieldValue_0) AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = @__InstanceFieldValue_0"); } public override async Task Where_simple_closure_via_query_cache_nullable_type(bool isAsync) @@ -327,13 +327,13 @@ public override async Task Where_simple_closure_via_query_cache_nullable_type(bo SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (CAST([e].[ReportsTo] AS bigint) = @__p_0) AND [e].[ReportsTo] IS NOT NULL", +WHERE CAST([e].[ReportsTo] AS bigint) = @__p_0", // @"@__p_0='5' (Nullable = true) SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (CAST([e].[ReportsTo] AS bigint) = @__p_0) AND [e].[ReportsTo] IS NOT NULL", +WHERE CAST([e].[ReportsTo] AS bigint) = @__p_0", // @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] @@ -353,13 +353,13 @@ FROM [Employees] AS [e] SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (CAST([e].[ReportsTo] AS bigint) = @__p_0) AND [e].[ReportsTo] IS NOT NULL", +WHERE CAST([e].[ReportsTo] AS bigint) = @__p_0", // @"@__p_0='2' (Nullable = true) SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (CAST([e].[ReportsTo] AS bigint) = @__p_0) AND [e].[ReportsTo] IS NOT NULL"); +WHERE CAST([e].[ReportsTo] AS bigint) = @__p_0"); } public override void Where_subquery_closure_via_query_cache() @@ -374,7 +374,7 @@ FROM [Customers] AS [c] WHERE EXISTS ( SELECT 1 FROM [Orders] AS [o] - WHERE (([o].[CustomerID] = @__customerID_0) AND [o].[CustomerID] IS NOT NULL) AND (([o].[CustomerID] = [c].[CustomerID]) AND [o].[CustomerID] IS NOT NULL))", + WHERE ([o].[CustomerID] = @__customerID_0) AND ([o].[CustomerID] = [c].[CustomerID]))", // @"@__customerID_0='ANATR' (Size = 5) @@ -383,7 +383,7 @@ FROM [Customers] AS [c] WHERE EXISTS ( SELECT 1 FROM [Orders] AS [o] - WHERE (([o].[CustomerID] = @__customerID_0) AND [o].[CustomerID] IS NOT NULL) AND (([o].[CustomerID] = [c].[CustomerID]) AND [o].[CustomerID] IS NOT NULL))"); + WHERE ([o].[CustomerID] = @__customerID_0) AND ([o].[CustomerID] = [c].[CustomerID]))"); } public override async Task Where_bitwise_or(bool isAsync) @@ -434,7 +434,7 @@ public override async Task Where_simple_shadow(bool isAsync) AssertSql( @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE ([e].[Title] = N'Sales Representative') AND [e].[Title] IS NOT NULL"); +WHERE [e].[Title] = N'Sales Representative'"); } public override async Task Where_simple_shadow_projection(bool isAsync) @@ -444,7 +444,7 @@ public override async Task Where_simple_shadow_projection(bool isAsync) AssertSql( @"SELECT [e].[Title] FROM [Employees] AS [e] -WHERE ([e].[Title] = N'Sales Representative') AND [e].[Title] IS NOT NULL"); +WHERE [e].[Title] = N'Sales Representative'"); } public override async Task Where_shadow_subquery_FirstOrDefault(bool isAsync) @@ -482,7 +482,7 @@ public override async Task Where_equals_method_string(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL"); +WHERE [c].[City] = N'London'"); } public override async Task Where_equals_method_int(bool isAsync) @@ -579,13 +579,13 @@ public override async Task Where_equals_on_mismatched_types_int_nullable_int(boo SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE ([e].[ReportsTo] = @__intPrm_0) AND [e].[ReportsTo] IS NOT NULL", +WHERE [e].[ReportsTo] = @__intPrm_0", // @"@__intPrm_0='2' SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (@__intPrm_0 = [e].[ReportsTo]) AND [e].[ReportsTo] IS NOT NULL"); +WHERE @__intPrm_0 = [e].[ReportsTo]"); } public override async Task Where_equals_on_matched_nullable_int_types(bool isAsync) @@ -597,13 +597,13 @@ public override async Task Where_equals_on_matched_nullable_int_types(bool isAsy SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (@__nullableIntPrm_0 = [e].[ReportsTo]) AND [e].[ReportsTo] IS NOT NULL", +WHERE @__nullableIntPrm_0 = [e].[ReportsTo]", // @"@__nullableIntPrm_0='2' (Nullable = true) SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE ([e].[ReportsTo] = @__nullableIntPrm_0) AND [e].[ReportsTo] IS NOT NULL"); +WHERE [e].[ReportsTo] = @__nullableIntPrm_0"); } public override async Task Where_equals_on_null_nullable_int_types(bool isAsync) @@ -627,7 +627,7 @@ public override async Task Where_comparison_nullable_type_not_null(bool isAsync) AssertSql( @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE ([e].[ReportsTo] = 2) AND [e].[ReportsTo] IS NOT NULL"); +WHERE [e].[ReportsTo] = 2"); } public override async Task Where_comparison_nullable_type_null(bool isAsync) @@ -647,7 +647,7 @@ public override async Task Where_string_length(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (CAST(LEN([c].[City]) AS int) = 6) AND LEN([c].[City]) IS NOT NULL"); +WHERE CAST(LEN([c].[City]) AS int) = 6"); } public override async Task Where_string_indexof(bool isAsync) @@ -673,7 +673,7 @@ public override async Task Where_string_replace(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (REPLACE([c].[City], N'Sea', N'Rea') = N'Reattle') AND REPLACE([c].[City], N'Sea', N'Rea') IS NOT NULL"); +WHERE REPLACE([c].[City], N'Sea', N'Rea') = N'Reattle'"); } public override async Task Where_string_substring(bool isAsync) @@ -683,7 +683,7 @@ public override async Task Where_string_substring(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (SUBSTRING([c].[City], 1 + 1, 2) = N'ea') AND SUBSTRING([c].[City], 1 + 1, 2) IS NOT NULL"); +WHERE SUBSTRING([c].[City], 1 + 1, 2) = N'ea'"); } public override async Task Where_datetime_now(bool isAsync) @@ -719,7 +719,7 @@ public override async Task Where_datetime_today(bool isAsync) AssertSql( @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE CONVERT(date, GETDATE()) = CONVERT(date, GETDATE())"); +WHERE (CONVERT(date, GETDATE()) = CONVERT(date, GETDATE())) OR CONVERT(date, GETDATE()) IS NULL"); } public override async Task Where_datetime_date_component(bool isAsync) @@ -731,7 +731,7 @@ public override async Task Where_datetime_date_component(bool isAsync) SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (CONVERT(date, [o].[OrderDate]) = @__myDatetime_0) AND CONVERT(date, [o].[OrderDate]) IS NOT NULL"); +WHERE CONVERT(date, [o].[OrderDate]) = @__myDatetime_0"); } public override async Task Where_date_add_year_constant_component(bool isAsync) @@ -741,7 +741,7 @@ public override async Task Where_date_add_year_constant_component(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (DATEPART(year, DATEADD(year, CAST(-1 AS int), [o].[OrderDate])) = 1997) AND DATEPART(year, DATEADD(year, CAST(-1 AS int), [o].[OrderDate])) IS NOT NULL"); +WHERE DATEPART(year, DATEADD(year, CAST(-1 AS int), [o].[OrderDate])) = 1997"); } public override async Task Where_datetime_year_component(bool isAsync) @@ -751,7 +751,7 @@ public override async Task Where_datetime_year_component(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (DATEPART(year, [o].[OrderDate]) = 1998) AND DATEPART(year, [o].[OrderDate]) IS NOT NULL"); +WHERE DATEPART(year, [o].[OrderDate]) = 1998"); } public override async Task Where_datetime_month_component(bool isAsync) @@ -761,7 +761,7 @@ public override async Task Where_datetime_month_component(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (DATEPART(month, [o].[OrderDate]) = 4) AND DATEPART(month, [o].[OrderDate]) IS NOT NULL"); +WHERE DATEPART(month, [o].[OrderDate]) = 4"); } public override async Task Where_datetime_dayOfYear_component(bool isAsync) @@ -771,7 +771,7 @@ public override async Task Where_datetime_dayOfYear_component(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (DATEPART(dayofyear, [o].[OrderDate]) = 68) AND DATEPART(dayofyear, [o].[OrderDate]) IS NOT NULL"); +WHERE DATEPART(dayofyear, [o].[OrderDate]) = 68"); } public override async Task Where_datetime_day_component(bool isAsync) @@ -781,7 +781,7 @@ public override async Task Where_datetime_day_component(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (DATEPART(day, [o].[OrderDate]) = 4) AND DATEPART(day, [o].[OrderDate]) IS NOT NULL"); +WHERE DATEPART(day, [o].[OrderDate]) = 4"); } public override async Task Where_datetime_hour_component(bool isAsync) @@ -791,7 +791,7 @@ public override async Task Where_datetime_hour_component(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (DATEPART(hour, [o].[OrderDate]) = 14) AND DATEPART(hour, [o].[OrderDate]) IS NOT NULL"); +WHERE DATEPART(hour, [o].[OrderDate]) = 14"); } public override async Task Where_datetime_minute_component(bool isAsync) @@ -801,7 +801,7 @@ public override async Task Where_datetime_minute_component(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (DATEPART(minute, [o].[OrderDate]) = 23) AND DATEPART(minute, [o].[OrderDate]) IS NOT NULL"); +WHERE DATEPART(minute, [o].[OrderDate]) = 23"); } public override async Task Where_datetime_second_component(bool isAsync) @@ -811,7 +811,7 @@ public override async Task Where_datetime_second_component(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (DATEPART(second, [o].[OrderDate]) = 44) AND DATEPART(second, [o].[OrderDate]) IS NOT NULL"); +WHERE DATEPART(second, [o].[OrderDate]) = 44"); } public override async Task Where_datetime_millisecond_component(bool isAsync) @@ -821,7 +821,7 @@ public override async Task Where_datetime_millisecond_component(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (DATEPART(millisecond, [o].[OrderDate]) = 88) AND DATEPART(millisecond, [o].[OrderDate]) IS NOT NULL"); +WHERE DATEPART(millisecond, [o].[OrderDate]) = 88"); } public override async Task Where_datetimeoffset_now_component(bool isAsync) @@ -853,7 +853,7 @@ public override async Task Where_simple_reversed(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (N'London' = [c].[City]) AND [c].[City] IS NOT NULL"); +WHERE N'London' = [c].[City]"); } public override async Task Where_is_null(bool isAsync) @@ -921,7 +921,7 @@ public override async Task Where_identity_comparison(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (([c].[City] = [c].[City]) AND ([c].[City] IS NOT NULL AND [c].[City] IS NOT NULL)) OR ([c].[City] IS NULL AND [c].[City] IS NULL)"); +WHERE ([c].[City] = [c].[City]) OR [c].[City] IS NULL"); } public override async Task Where_in_optimization_multiple(bool isAsync) @@ -932,7 +932,7 @@ public override async Task Where_in_optimization_multiple(bool isAsync) @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Customers] AS [c] CROSS JOIN [Employees] AS [e] -WHERE (((([c].[City] = N'London') AND [c].[City] IS NOT NULL) OR (([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL)) OR ([c].[CustomerID] = N'ALFKI')) OR ([c].[CustomerID] = N'ABCDE')"); +WHERE ((([c].[City] = N'London') OR ([c].[City] = N'Berlin')) OR ([c].[CustomerID] = N'ALFKI')) OR ([c].[CustomerID] = N'ABCDE')"); } public override async Task Where_not_in_optimization1(bool isAsync) @@ -987,7 +987,7 @@ public override async Task Where_select_many_and(bool isAsync) @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Customers] AS [c] CROSS JOIN [Employees] AS [e] -WHERE ((([c].[City] = N'London') AND [c].[City] IS NOT NULL) AND (([c].[Country] = N'UK') AND [c].[Country] IS NOT NULL)) AND ((([e].[City] = N'London') AND [e].[City] IS NOT NULL) AND (([e].[Country] = N'UK') AND [e].[Country] IS NOT NULL))"); +WHERE (([c].[City] = N'London') AND ([c].[Country] = N'UK')) AND (([e].[City] = N'London') AND ([e].[Country] = N'UK'))"); } public override async Task Where_primitive(bool isAsync) @@ -1105,8 +1105,7 @@ public override async Task Where_not_bool_member_compared_to_not_bool_member(boo AssertSql( @"SELECT [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock] -FROM [Products] AS [p] -WHERE [p].[Discontinued] = [p].[Discontinued]"); +FROM [Products] AS [p]"); } public override async Task Where_negated_boolean_expression_compared_to_another_negated_boolean_expression(bool isAsync) @@ -1280,7 +1279,7 @@ public override async Task Where_expression_invoke_2(bool isAsync) @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] -WHERE ([c].[CustomerID] = N'ALFKI') AND [c].[CustomerID] IS NOT NULL"); +WHERE [c].[CustomerID] = N'ALFKI'"); } public override async Task Where_concat_string_int_comparison1(bool isAsync) @@ -1292,7 +1291,7 @@ public override async Task Where_concat_string_int_comparison1(bool isAsync) SELECT [c].[CustomerID] FROM [Customers] AS [c] -WHERE (([c].[CustomerID] + CAST(@__i_0 AS nchar(5))) = [c].[CompanyName]) AND [c].[CompanyName] IS NOT NULL"); +WHERE ([c].[CustomerID] + CAST(@__i_0 AS nchar(5))) = [c].[CompanyName]"); } public override async Task Where_concat_string_int_comparison2(bool isAsync) @@ -1304,7 +1303,7 @@ public override async Task Where_concat_string_int_comparison2(bool isAsync) SELECT [c].[CustomerID] FROM [Customers] AS [c] -WHERE ((CAST(@__i_0 AS nchar(5)) + [c].[CustomerID]) = [c].[CompanyName]) AND [c].[CompanyName] IS NOT NULL"); +WHERE (CAST(@__i_0 AS nchar(5)) + [c].[CustomerID]) = [c].[CompanyName]"); } public override async Task Where_concat_string_int_comparison3(bool isAsync) @@ -1317,7 +1316,7 @@ public override async Task Where_concat_string_int_comparison3(bool isAsync) SELECT [c].[CustomerID] FROM [Customers] AS [c] -WHERE ((((CAST(@__p_0 AS nchar(5)) + [c].[CustomerID]) + CAST(@__j_1 AS nchar(5))) + CAST(42 AS nchar(5))) = [c].[CompanyName]) AND [c].[CompanyName] IS NOT NULL"); +WHERE (((CAST(@__p_0 AS nchar(5)) + [c].[CustomerID]) + CAST(@__j_1 AS nchar(5))) + CAST(42 AS nchar(5))) = [c].[CompanyName]"); } public override async Task Where_concat_string_int_comparison4(bool isAsync) @@ -1327,7 +1326,7 @@ public override async Task Where_concat_string_int_comparison4(bool isAsync) AssertSql( @"SELECT [o].[CustomerID] FROM [Orders] AS [o] -WHERE (((CAST([o].[OrderID] AS nchar(5)) + [o].[CustomerID]) = [o].[CustomerID]) AND ([o].[CustomerID] IS NOT NULL AND [o].[CustomerID] IS NOT NULL)) OR ([o].[CustomerID] IS NULL AND [o].[CustomerID] IS NULL)"); +WHERE ((CAST([o].[OrderID] AS nchar(5)) + [o].[CustomerID]) = [o].[CustomerID]) OR [o].[CustomerID] IS NULL"); } public override async Task Where_concat_string_string_comparison(bool isAsync) @@ -1339,7 +1338,7 @@ public override async Task Where_concat_string_string_comparison(bool isAsync) SELECT [c].[CustomerID] FROM [Customers] AS [c] -WHERE ((@__i_0 + [c].[CustomerID]) = [c].[CompanyName]) AND [c].[CompanyName] IS NOT NULL"); +WHERE (@__i_0 + [c].[CustomerID]) = [c].[CompanyName]"); } public override async Task Where_string_concat_method_comparison(bool isAsync) @@ -1351,7 +1350,7 @@ public override async Task Where_string_concat_method_comparison(bool isAsync) SELECT [c].[CustomerID] FROM [Customers] AS [c] -WHERE ((@__i_0 + [c].[CustomerID]) = [c].[CompanyName]) AND [c].[CompanyName] IS NOT NULL"); +WHERE (@__i_0 + [c].[CustomerID]) = [c].[CompanyName]"); } public override async Task Where_ternary_boolean_condition_true(bool isAsync) @@ -1527,7 +1526,7 @@ public override async Task Where_compare_null(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[City] IS NULL AND (([c].[Country] = N'UK') AND [c].[Country] IS NOT NULL)"); +WHERE [c].[City] IS NULL AND ([c].[Country] = N'UK')"); } public override async Task Where_Is_on_same_type(bool isAsync) @@ -1546,7 +1545,7 @@ public override async Task Where_chain(bool isAsync) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'QUICK') AND [o].[CustomerID] IS NOT NULL) AND ([o].[OrderDate] > '1998-01-01T00:00:00.000')"); +WHERE ([o].[CustomerID] = N'QUICK') AND ([o].[OrderDate] > '1998-01-01T00:00:00.000')"); } public override void Where_navigation_contains() @@ -1632,7 +1631,7 @@ FROM [Customers] AS [c] WHERE [o].[OrderID] IN ( SELECT [o0].[OrderID] FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o0].[CustomerID] ) )"); } @@ -1647,7 +1646,7 @@ FROM [Customers] AS [c] WHERE ( SELECT TOP(1) [o].[OrderID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID]) IS NULL"); } @@ -1658,15 +1657,11 @@ public override async Task Where_subquery_FirstOrDefault_compared_to_entity(bool AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (( - SELECT TOP(1) [o].[OrderID] - FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL - ORDER BY [o].[OrderID]) = 10243) AND ( +WHERE ( SELECT TOP(1) [o].[OrderID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL - ORDER BY [o].[OrderID]) IS NOT NULL"); + WHERE [c].[CustomerID] = [o].[CustomerID] + ORDER BY [o].[OrderID]) = 10243"); } public override async Task Time_of_day_datetime(bool isAsync) @@ -1761,7 +1756,7 @@ public override async Task Project_non_nullable_value_after_FirstOrDefault_on_em @"SELECT ( SELECT TOP(1) CAST(LEN([o].[CustomerID]) AS int) FROM [Orders] AS [o] - WHERE ([o].[CustomerID] = N'John Doe') AND [o].[CustomerID] IS NOT NULL) + WHERE [o].[CustomerID] = N'John Doe') FROM [Customers] AS [c]"); } @@ -1772,13 +1767,10 @@ public override async Task Filter_non_nullable_value_after_FirstOrDefault_on_emp AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (( - SELECT TOP(1) CAST(LEN([o].[CustomerID]) AS int) - FROM [Orders] AS [o] - WHERE ([o].[CustomerID] = N'John Doe') AND [o].[CustomerID] IS NOT NULL) = 0) AND ( +WHERE ( SELECT TOP(1) CAST(LEN([o].[CustomerID]) AS int) FROM [Orders] AS [o] - WHERE ([o].[CustomerID] = N'John Doe') AND [o].[CustomerID] IS NOT NULL) IS NOT NULL"); + WHERE [o].[CustomerID] = N'John Doe') = 0"); } public override async Task Like_with_non_string_column_using_ToString(bool isAsync) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.cs index e37e559c72d..3aa2642e70e 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.cs @@ -151,8 +151,7 @@ public override async Task Entity_equality_self(bool isAsync) AssertSql( @"SELECT [c].[CustomerID] -FROM [Customers] AS [c] -WHERE [c].[CustomerID] = [c].[CustomerID]"); +FROM [Customers] AS [c]"); } public override async Task Entity_equality_local(bool isAsync) @@ -303,7 +302,7 @@ FROM [Customers] AS [c] WHERE ( SELECT TOP(1) [o].[OrderID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) IS NOT NULL"); + WHERE [c].[CustomerID] = [o].[CustomerID]) IS NOT NULL"); } public override async Task Entity_equality_through_include(bool isAsync) @@ -458,7 +457,7 @@ ORDER BY [e].[EmployeeID] WHERE ( SELECT TOP(1) [e0].[EmployeeID] FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] = [t].[ReportsTo]) AND [t].[ReportsTo] IS NOT NULL) IS NULL + WHERE [e0].[EmployeeID] = [t].[ReportsTo]) IS NULL ORDER BY [t].[EmployeeID]"); } @@ -480,7 +479,7 @@ OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY WHERE ( SELECT TOP(1) [e0].[EmployeeID] FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] = [t].[ReportsTo]) AND [t].[ReportsTo] IS NOT NULL) IS NOT NULL + WHERE [e0].[EmployeeID] = [t].[ReportsTo]) IS NOT NULL ORDER BY [t].[EmployeeID]"); } @@ -491,13 +490,10 @@ public override async Task Where_query_composition_entity_equality_one_element_S AssertSql( @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (( - SELECT TOP(1) [e0].[EmployeeID] - FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] = [e].[ReportsTo]) AND [e].[ReportsTo] IS NOT NULL) = 0) AND ( +WHERE ( SELECT TOP(1) [e0].[EmployeeID] FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] = [e].[ReportsTo]) AND [e].[ReportsTo] IS NOT NULL) IS NOT NULL"); + WHERE [e0].[EmployeeID] = [e].[ReportsTo]) = 0"); } public override async Task Where_query_composition_entity_equality_one_element_Single(bool isAsync) @@ -507,13 +503,10 @@ public override async Task Where_query_composition_entity_equality_one_element_S AssertSql( @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (( - SELECT TOP(1) [e0].[EmployeeID] - FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] = [e].[ReportsTo]) AND [e].[ReportsTo] IS NOT NULL) = 0) AND ( +WHERE ( SELECT TOP(1) [e0].[EmployeeID] FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] = [e].[ReportsTo]) AND [e].[ReportsTo] IS NOT NULL) IS NOT NULL"); + WHERE [e0].[EmployeeID] = [e].[ReportsTo]) = 0"); } public override async Task Where_query_composition_entity_equality_one_element_FirstOrDefault(bool isAsync) @@ -523,13 +516,10 @@ public override async Task Where_query_composition_entity_equality_one_element_F AssertSql( @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (( - SELECT TOP(1) [e0].[EmployeeID] - FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] = [e].[ReportsTo]) AND [e].[ReportsTo] IS NOT NULL) = 0) AND ( +WHERE ( SELECT TOP(1) [e0].[EmployeeID] FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] = [e].[ReportsTo]) AND [e].[ReportsTo] IS NOT NULL) IS NOT NULL"); + WHERE [e0].[EmployeeID] = [e].[ReportsTo]) = 0"); } public override async Task Where_query_composition_entity_equality_one_element_First(bool isAsync) @@ -539,13 +529,10 @@ public override async Task Where_query_composition_entity_equality_one_element_F AssertSql( @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (( - SELECT TOP(1) [e0].[EmployeeID] - FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] = [e].[ReportsTo]) AND [e].[ReportsTo] IS NOT NULL) = 0) AND ( +WHERE ( SELECT TOP(1) [e0].[EmployeeID] FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] = [e].[ReportsTo]) AND [e].[ReportsTo] IS NOT NULL) IS NOT NULL"); + WHERE [e0].[EmployeeID] = [e].[ReportsTo]) = 0"); } public override async Task Where_query_composition_entity_equality_no_elements_SingleOrDefault(bool isAsync) @@ -555,13 +542,10 @@ public override async Task Where_query_composition_entity_equality_no_elements_S AssertSql( @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (( - SELECT TOP(1) [e0].[EmployeeID] - FROM [Employees] AS [e0] - WHERE [e0].[EmployeeID] = 42) = 0) AND ( +WHERE ( SELECT TOP(1) [e0].[EmployeeID] FROM [Employees] AS [e0] - WHERE [e0].[EmployeeID] = 42) IS NOT NULL"); + WHERE [e0].[EmployeeID] = 42) = 0"); } public override async Task Where_query_composition_entity_equality_no_elements_Single(bool isAsync) @@ -571,13 +555,10 @@ public override async Task Where_query_composition_entity_equality_no_elements_S AssertSql( @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (( - SELECT TOP(1) [e0].[EmployeeID] - FROM [Employees] AS [e0] - WHERE [e0].[EmployeeID] = 42) = 0) AND ( +WHERE ( SELECT TOP(1) [e0].[EmployeeID] FROM [Employees] AS [e0] - WHERE [e0].[EmployeeID] = 42) IS NOT NULL"); + WHERE [e0].[EmployeeID] = 42) = 0"); } public override async Task Where_query_composition_entity_equality_no_elements_FirstOrDefault(bool isAsync) @@ -587,13 +568,10 @@ public override async Task Where_query_composition_entity_equality_no_elements_F AssertSql( @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (( - SELECT TOP(1) [e0].[EmployeeID] - FROM [Employees] AS [e0] - WHERE [e0].[EmployeeID] = 42) = 0) AND ( +WHERE ( SELECT TOP(1) [e0].[EmployeeID] FROM [Employees] AS [e0] - WHERE [e0].[EmployeeID] = 42) IS NOT NULL"); + WHERE [e0].[EmployeeID] = 42) = 0"); } public override async Task Where_query_composition_entity_equality_no_elements_First(bool isAsync) @@ -603,13 +581,10 @@ public override async Task Where_query_composition_entity_equality_no_elements_F AssertSql( @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (( - SELECT TOP(1) [e0].[EmployeeID] - FROM [Employees] AS [e0] - WHERE [e0].[EmployeeID] = 42) = 0) AND ( +WHERE ( SELECT TOP(1) [e0].[EmployeeID] FROM [Employees] AS [e0] - WHERE [e0].[EmployeeID] = 42) IS NOT NULL"); + WHERE [e0].[EmployeeID] = 42) = 0"); } public override async Task Where_query_composition_entity_equality_multiple_elements_SingleOrDefault(bool isAsync) @@ -619,13 +594,10 @@ public override async Task Where_query_composition_entity_equality_multiple_elem AssertSql( @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (( - SELECT TOP(1) [e0].[EmployeeID] - FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] <> [e].[ReportsTo]) OR [e].[ReportsTo] IS NULL) = 0) AND ( +WHERE ( SELECT TOP(1) [e0].[EmployeeID] FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] <> [e].[ReportsTo]) OR [e].[ReportsTo] IS NULL) IS NOT NULL"); + WHERE ([e0].[EmployeeID] <> [e].[ReportsTo]) OR [e].[ReportsTo] IS NULL) = 0"); } public override async Task Where_query_composition_entity_equality_multiple_elements_Single(bool isAsync) @@ -635,13 +607,10 @@ public override async Task Where_query_composition_entity_equality_multiple_elem AssertSql( @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (( - SELECT TOP(1) [e0].[EmployeeID] - FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] <> [e].[ReportsTo]) OR [e].[ReportsTo] IS NULL) = 0) AND ( +WHERE ( SELECT TOP(1) [e0].[EmployeeID] FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] <> [e].[ReportsTo]) OR [e].[ReportsTo] IS NULL) IS NOT NULL"); + WHERE ([e0].[EmployeeID] <> [e].[ReportsTo]) OR [e].[ReportsTo] IS NULL) = 0"); } public override async Task Where_query_composition_entity_equality_multiple_elements_FirstOrDefault(bool isAsync) @@ -651,13 +620,10 @@ public override async Task Where_query_composition_entity_equality_multiple_elem AssertSql( @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (( - SELECT TOP(1) [e0].[EmployeeID] - FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] <> [e].[ReportsTo]) OR [e].[ReportsTo] IS NULL) = 0) AND ( +WHERE ( SELECT TOP(1) [e0].[EmployeeID] FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] <> [e].[ReportsTo]) OR [e].[ReportsTo] IS NULL) IS NOT NULL"); + WHERE ([e0].[EmployeeID] <> [e].[ReportsTo]) OR [e].[ReportsTo] IS NULL) = 0"); } public override async Task Where_query_composition_entity_equality_multiple_elements_First(bool isAsync) @@ -667,13 +633,10 @@ public override async Task Where_query_composition_entity_equality_multiple_elem AssertSql( @"SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE (( - SELECT TOP(1) [e0].[EmployeeID] - FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] <> [e].[ReportsTo]) OR [e].[ReportsTo] IS NULL) = 0) AND ( +WHERE ( SELECT TOP(1) [e0].[EmployeeID] FROM [Employees] AS [e0] - WHERE ([e0].[EmployeeID] <> [e].[ReportsTo]) OR [e].[ReportsTo] IS NULL) IS NOT NULL"); + WHERE ([e0].[EmployeeID] <> [e].[ReportsTo]) OR [e].[ReportsTo] IS NULL) = 0"); } public override async Task Where_query_composition2(bool isAsync) @@ -688,13 +651,10 @@ public override async Task Where_query_composition2(bool isAsync) SELECT TOP(@__p_0) [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] ) AS [t] -WHERE (([t].[FirstName] = ( - SELECT TOP(1) [e0].[FirstName] - FROM [Employees] AS [e0] - ORDER BY [e0].[EmployeeID])) AND ([t].[FirstName] IS NOT NULL AND ( +WHERE ([t].[FirstName] = ( SELECT TOP(1) [e0].[FirstName] FROM [Employees] AS [e0] - ORDER BY [e0].[EmployeeID]) IS NOT NULL)) OR ([t].[FirstName] IS NULL AND ( + ORDER BY [e0].[EmployeeID])) OR ([t].[FirstName] IS NULL AND ( SELECT TOP(1) [e0].[FirstName] FROM [Employees] AS [e0] ORDER BY [e0].[EmployeeID]) IS NULL)"); @@ -775,19 +735,13 @@ public override void Select_Where_Subquery_Deep_Single() SELECT TOP(@__p_0) [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice] FROM [Order Details] AS [o] -WHERE ([o].[OrderID] = 10344) AND ((( - SELECT TOP(1) ( - SELECT TOP(1) [c].[City] - FROM [Customers] AS [c] - WHERE ([o0].[CustomerID] = [c].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL) - FROM [Orders] AS [o0] - WHERE [o].[OrderID] = [o0].[OrderID]) = N'Seattle') AND ( +WHERE ([o].[OrderID] = 10344) AND (( SELECT TOP(1) ( SELECT TOP(1) [c].[City] FROM [Customers] AS [c] - WHERE ([o0].[CustomerID] = [c].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL) + WHERE [o0].[CustomerID] = [c].[CustomerID]) FROM [Orders] AS [o0] - WHERE [o].[OrderID] = [o0].[OrderID]) IS NOT NULL)"); + WHERE [o].[OrderID] = [o0].[OrderID]) = N'Seattle')"); } public override void Select_Where_Subquery_Deep_First() @@ -799,19 +753,13 @@ public override void Select_Where_Subquery_Deep_First() SELECT TOP(@__p_0) [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice] FROM [Order Details] AS [o] -WHERE (( - SELECT TOP(1) ( - SELECT TOP(1) [c].[City] - FROM [Customers] AS [c] - WHERE ([o0].[CustomerID] = [c].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL) - FROM [Orders] AS [o0] - WHERE [o].[OrderID] = [o0].[OrderID]) = N'Seattle') AND ( +WHERE ( SELECT TOP(1) ( SELECT TOP(1) [c].[City] FROM [Customers] AS [c] - WHERE ([o0].[CustomerID] = [c].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL) + WHERE [o0].[CustomerID] = [c].[CustomerID]) FROM [Orders] AS [o0] - WHERE [o].[OrderID] = [o0].[OrderID]) IS NOT NULL"); + WHERE [o].[OrderID] = [o0].[OrderID]) = N'Seattle'"); } public override void Select_Where_Subquery_Equality() @@ -834,28 +782,19 @@ SELECT TOP(2) [o0].[OrderID], [o0].[ProductID], [o0].[Discount], [o0].[Quantity] FROM [Order Details] AS [o0] ORDER BY [o0].[OrderID] ) AS [t0] - WHERE ((( + WHERE (( SELECT TOP(1) [c].[Country] FROM [Customers] AS [c] - WHERE ([c].[CustomerID] = [t].[CustomerID]) AND [t].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [t].[CustomerID] ORDER BY [c].[CustomerID]) = ( SELECT TOP(1) [c0].[Country] FROM [Orders] AS [o1] INNER JOIN [Customers] AS [c0] ON [o1].[CustomerID] = [c0].[CustomerID] WHERE [o1].[OrderID] = [t0].[OrderID] - ORDER BY [o1].[OrderID], [c0].[CustomerID])) AND (( - SELECT TOP(1) [c].[Country] - FROM [Customers] AS [c] - WHERE ([c].[CustomerID] = [t].[CustomerID]) AND [t].[CustomerID] IS NOT NULL - ORDER BY [c].[CustomerID]) IS NOT NULL AND ( - SELECT TOP(1) [c0].[Country] - FROM [Orders] AS [o1] - INNER JOIN [Customers] AS [c0] ON [o1].[CustomerID] = [c0].[CustomerID] - WHERE [o1].[OrderID] = [t0].[OrderID] - ORDER BY [o1].[OrderID], [c0].[CustomerID]) IS NOT NULL)) OR (( + ORDER BY [o1].[OrderID], [c0].[CustomerID])) OR (( SELECT TOP(1) [c].[Country] FROM [Customers] AS [c] - WHERE ([c].[CustomerID] = [t].[CustomerID]) AND [t].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [t].[CustomerID] ORDER BY [c].[CustomerID]) IS NULL AND ( SELECT TOP(1) [c0].[Country] FROM [Orders] AS [o1] @@ -883,7 +822,7 @@ SELECT TOP(5) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] ORDER BY [o].[OrderID] ) AS [t0] -WHERE ([t].[EmployeeID] = [t0].[EmployeeID]) AND [t0].[EmployeeID] IS NOT NULL +WHERE [t].[EmployeeID] = [t0].[EmployeeID] ORDER BY [t].[EmployeeID]"); } @@ -910,7 +849,7 @@ CROSS JOIN ( SELECT TOP(@__p_1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] ) AS [t1] -WHERE ([t].[City] = N'Seattle') AND [t].[City] IS NOT NULL +WHERE [t].[City] = N'Seattle' ORDER BY [t].[EmployeeID]"); } @@ -926,7 +865,7 @@ SELECT TOP(3) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] ORDER BY [o].[OrderID] ) AS [t] -WHERE ([c].[CustomerID] = [t].[CustomerID]) AND [t].[CustomerID] IS NOT NULL +WHERE [c].[CustomerID] = [t].[CustomerID] ORDER BY [c].[CustomerID]"); } @@ -939,7 +878,7 @@ public override async Task Let_any_subquery_anonymous(bool isAsync) WHEN EXISTS ( SELECT 1 FROM [Orders] AS [o] - WHERE ([o].[CustomerID] = [c].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) THEN CAST(1 AS bit) + WHERE [o].[CustomerID] = [c].[CustomerID]) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [hasOrders] FROM [Customers] AS [c] @@ -995,7 +934,7 @@ ORDER BY CASE WHEN EXISTS ( SELECT 1 FROM [Orders] AS [o] - WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND ([o].[OrderID] > 11000)) THEN CAST(1 AS bit) + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND ([o].[OrderID] > 11000)) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END, [c].[CustomerID]"); } @@ -1229,7 +1168,7 @@ SELECT COUNT(*) FROM ( SELECT TOP(@__p_0) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([o].[CustomerID] = N'FRANK') AND [o].[CustomerID] IS NOT NULL + WHERE [o].[CustomerID] = N'FRANK' ) AS [t] ) AS [t0]"); } @@ -1472,10 +1411,10 @@ public override void Any_with_multiple_conditions_still_uses_exists() AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (([c].[City] = N'London') AND [c].[City] IS NOT NULL) AND EXISTS ( +WHERE ([c].[City] = N'London') AND EXISTS ( SELECT 1 FROM [Orders] AS [o] - WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND (([o].[EmployeeID] = 1) AND [o].[EmployeeID] IS NOT NULL))"); + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND ([o].[EmployeeID] = 1))"); } public override async Task All_top_level(bool isAsync) @@ -1502,7 +1441,7 @@ public override async Task All_top_level_column(bool isAsync) WHEN NOT EXISTS ( SELECT 1 FROM [Customers] AS [c] - WHERE (([c].[ContactName] <> N'') OR [c].[ContactName] IS NULL) AND ([c].[ContactName] IS NULL OR (LEFT([c].[ContactName], LEN([c].[ContactName])) <> [c].[ContactName]))) THEN CAST(1 AS bit) + WHERE (([c].[ContactName] <> N'') OR [c].[ContactName] IS NULL) AND ([c].[ContactName] IS NULL OR ([c].[ContactName] IS NULL OR ((LEFT([c].[ContactName], LEN([c].[ContactName])) <> [c].[ContactName]) OR LEFT([c].[ContactName], LEN([c].[ContactName])) IS NULL)))) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END"); } @@ -1555,7 +1494,7 @@ public override async Task Where_select_many_or(bool isAsync) @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Customers] AS [c] CROSS JOIN [Employees] AS [e] -WHERE (([c].[City] = N'London') AND [c].[City] IS NOT NULL) OR (([e].[City] = N'London') AND [e].[City] IS NOT NULL)"); +WHERE ([c].[City] = N'London') OR ([e].[City] = N'London')"); } public override async Task Where_select_many_or2(bool isAsync) @@ -1566,7 +1505,7 @@ public override async Task Where_select_many_or2(bool isAsync) @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Customers] AS [c] CROSS JOIN [Employees] AS [e] -WHERE (([c].[City] = N'London') AND [c].[City] IS NOT NULL) OR (([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL)"); +WHERE ([c].[City] = N'London') OR ([c].[City] = N'Berlin')"); } public override async Task Where_select_many_or3(bool isAsync) @@ -1577,7 +1516,7 @@ public override async Task Where_select_many_or3(bool isAsync) @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Customers] AS [c] CROSS JOIN [Employees] AS [e] -WHERE ((([c].[City] = N'London') AND [c].[City] IS NOT NULL) OR (([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL)) OR (([c].[City] = N'Seattle') AND [c].[City] IS NOT NULL)"); +WHERE (([c].[City] = N'London') OR ([c].[City] = N'Berlin')) OR ([c].[City] = N'Seattle')"); } public override async Task Where_select_many_or4(bool isAsync) @@ -1588,7 +1527,7 @@ public override async Task Where_select_many_or4(bool isAsync) @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Customers] AS [c] CROSS JOIN [Employees] AS [e] -WHERE (((([c].[City] = N'London') AND [c].[City] IS NOT NULL) OR (([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL)) OR (([c].[City] = N'Seattle') AND [c].[City] IS NOT NULL)) OR (([c].[City] = N'Lisboa') AND [c].[City] IS NOT NULL)"); +WHERE ((([c].[City] = N'London') OR ([c].[City] = N'Berlin')) OR ([c].[City] = N'Seattle')) OR ([c].[City] = N'Lisboa')"); } public override async Task Where_select_many_or_with_parameter(bool isAsync) @@ -1602,7 +1541,7 @@ public override async Task Where_select_many_or_with_parameter(bool isAsync) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Customers] AS [c] CROSS JOIN [Employees] AS [e] -WHERE (((([c].[City] = @__london_0) AND [c].[City] IS NOT NULL) OR (([c].[City] = N'Berlin') AND [c].[City] IS NOT NULL)) OR (([c].[City] = N'Seattle') AND [c].[City] IS NOT NULL)) OR (([c].[City] = @__lisboa_1) AND [c].[City] IS NOT NULL)"); +WHERE ((([c].[City] = @__london_0) OR ([c].[City] = N'Berlin')) OR ([c].[City] = N'Seattle')) OR ([c].[City] = @__lisboa_1)"); } public override async Task SelectMany_simple_subquery(bool isAsync) @@ -1729,7 +1668,7 @@ FROM [Customers] AS [c] WHERE ([c].[CustomerID] = N'ALFKI') AND EXISTS ( SELECT 1 FROM [Orders] AS [o] - WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND (([o].[OrderDate] = '2008-10-24T00:00:00.000') AND [o].[OrderDate] IS NOT NULL))"); + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND ([o].[OrderDate] = '2008-10-24T00:00:00.000'))"); } public override async Task Where_Join_Exists(bool isAsync) @@ -1805,7 +1744,7 @@ SELECT 1 FROM [Customers] AS [c] INNER JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] INNER JOIN [Order Details] AS [o0] ON [o].[OrderID] = [o0].[OrderID] - WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL) THEN CAST(1 AS bit) + WHERE [c].[City] = N'London') THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END"); } @@ -1877,7 +1816,7 @@ public override async Task SelectMany_cartesian_product_with_ordering(bool isAsy @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [e].[City] FROM [Customers] AS [c] CROSS JOIN [Employees] AS [e] -WHERE (([c].[City] = [e].[City]) AND ([c].[City] IS NOT NULL AND [e].[City] IS NOT NULL)) OR ([c].[City] IS NULL AND [e].[City] IS NULL) +WHERE ([c].[City] = [e].[City]) OR ([c].[City] IS NULL AND [e].[City] IS NULL) ORDER BY [e].[City], [c].[CustomerID] DESC"); } @@ -2358,7 +2297,7 @@ public override void Select_nested_collection_count_using_DTO() @"SELECT [c].[CustomerID] AS [Id], ( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AS [Count] + WHERE [c].[CustomerID] = [o].[CustomerID]) AS [Count] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%'"); } @@ -2626,7 +2565,7 @@ public override async Task Filter_coalesce_operator(bool isAsync) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE (COALESCE([c].[CompanyName], [c].[ContactName]) = N'The Big Cheese') AND ([c].[CompanyName] IS NOT NULL OR [c].[ContactName] IS NOT NULL)"); +WHERE COALESCE([c].[CompanyName], [c].[ContactName]) = N'The Big Cheese'"); } [SqlServerCondition(SqlServerCondition.SupportsOffset)] @@ -2929,7 +2868,7 @@ ELSE CAST(0 AS bit) END | CASE WHEN [c].[CustomerID] = N'ANATR' THEN CAST(1 AS bit) ELSE CAST(0 AS bit) -END) = CAST(1 AS bit)) AND (([c].[Country] = N'Germany') AND [c].[Country] IS NOT NULL)"); +END) = CAST(1 AS bit)) AND ([c].[Country] = N'Germany')"); } public override async Task Where_bitwise_and_with_logical_or(bool isAsync) @@ -3008,7 +2947,7 @@ public override async Task Parameter_extraction_short_circuits_1(bool isAsync) SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE ([o].[OrderID] < 10400) AND (([o].[OrderDate] IS NOT NULL AND ((DATEPART(month, [o].[OrderDate]) = @__dateFilter_Value_Month_0) AND DATEPART(month, [o].[OrderDate]) IS NOT NULL)) AND ((DATEPART(year, [o].[OrderDate]) = @__dateFilter_Value_Year_1) AND DATEPART(year, [o].[OrderDate]) IS NOT NULL))", +WHERE ([o].[OrderID] < 10400) AND (([o].[OrderDate] IS NOT NULL AND (DATEPART(month, [o].[OrderDate]) = @__dateFilter_Value_Month_0)) AND (DATEPART(year, [o].[OrderDate]) = @__dateFilter_Value_Year_1))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] @@ -3025,7 +2964,7 @@ public override async Task Parameter_extraction_short_circuits_2(bool isAsync) SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE ([o].[OrderID] < 10400) AND (([o].[OrderDate] IS NOT NULL AND ((DATEPART(month, [o].[OrderDate]) = @__dateFilter_Value_Month_0) AND DATEPART(month, [o].[OrderDate]) IS NOT NULL)) AND ((DATEPART(year, [o].[OrderDate]) = @__dateFilter_Value_Year_1) AND DATEPART(year, [o].[OrderDate]) IS NOT NULL))", +WHERE ([o].[OrderID] < 10400) AND (([o].[OrderDate] IS NOT NULL AND (DATEPART(month, [o].[OrderDate]) = @__dateFilter_Value_Month_0)) AND (DATEPART(year, [o].[OrderDate]) = @__dateFilter_Value_Year_1))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] @@ -3042,7 +2981,7 @@ public override async Task Parameter_extraction_short_circuits_3(bool isAsync) SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE ([o].[OrderID] < 10400) OR (([o].[OrderDate] IS NOT NULL AND ((DATEPART(month, [o].[OrderDate]) = @__dateFilter_Value_Month_0) AND DATEPART(month, [o].[OrderDate]) IS NOT NULL)) AND ((DATEPART(year, [o].[OrderDate]) = @__dateFilter_Value_Year_1) AND DATEPART(year, [o].[OrderDate]) IS NOT NULL))", +WHERE ([o].[OrderID] < 10400) OR (([o].[OrderDate] IS NOT NULL AND (DATEPART(month, [o].[OrderDate]) = @__dateFilter_Value_Month_0)) AND (DATEPART(year, [o].[OrderDate]) = @__dateFilter_Value_Year_1))", // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o]"); @@ -3058,7 +2997,7 @@ public override async Task Subquery_member_pushdown_does_not_change_original_sub SELECT [t].[OrderID] AS [OrderId], ( SELECT TOP(1) [c].[City] FROM [Customers] AS [c] - WHERE ([c].[CustomerID] = [t].[CustomerID]) AND [t].[CustomerID] IS NOT NULL) AS [City] + WHERE [c].[CustomerID] = [t].[CustomerID]) AS [City] FROM ( SELECT TOP(@__p_0) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] @@ -3067,7 +3006,7 @@ ORDER BY [o].[OrderID] ORDER BY ( SELECT TOP(1) [c0].[City] FROM [Customers] AS [c0] - WHERE ([c0].[CustomerID] = [t].[CustomerID]) AND [t].[CustomerID] IS NOT NULL)"); + WHERE [c0].[CustomerID] = [t].[CustomerID])"); } public override async Task Subquery_member_pushdown_does_not_change_original_subquery_model2(bool isAsync) @@ -3080,7 +3019,7 @@ public override async Task Subquery_member_pushdown_does_not_change_original_sub SELECT [t].[OrderID] AS [OrderId], ( SELECT TOP(1) [c].[City] FROM [Customers] AS [c] - WHERE ([c].[CustomerID] = [t].[CustomerID]) AND [t].[CustomerID] IS NOT NULL) AS [City] + WHERE [c].[CustomerID] = [t].[CustomerID]) AS [City] FROM ( SELECT TOP(@__p_0) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] @@ -3089,7 +3028,7 @@ ORDER BY [o].[OrderID] ORDER BY ( SELECT TOP(1) [c0].[City] FROM [Customers] AS [c0] - WHERE ([c0].[CustomerID] = [t].[CustomerID]) AND [t].[CustomerID] IS NOT NULL)"); + WHERE [c0].[CustomerID] = [t].[CustomerID])"); } public override async Task Query_expression_with_to_string_and_contains(bool isAsync) @@ -3252,7 +3191,7 @@ SELECT NULL AS [empty] LEFT JOIN ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] - WHERE ([c].[City] = N'London') AND [c].[City] IS NOT NULL + WHERE [c].[City] = N'London' ) AS [t] ON 1 = 1 WHERE [t].[CustomerID] IS NOT NULL"); } @@ -3307,7 +3246,7 @@ WHERE [o].[OrderID] > 15000 ) AS [t] ON 1 = 1 ) AS [t0] LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] -WHERE (([c].[City] = N'Seattle') AND [c].[City] IS NOT NULL) AND ([t0].[OrderID] IS NOT NULL AND [o0].[OrderID] IS NOT NULL) +WHERE ([c].[City] = N'Seattle') AND ([t0].[OrderID] IS NOT NULL AND [o0].[OrderID] IS NOT NULL) ORDER BY [t0].[OrderID], [o0].[OrderDate]"); } @@ -3594,7 +3533,7 @@ FROM [Orders] AS [o] SELECT [o0].[OrderID] FROM [Order Details] AS [o0] INNER JOIN [Products] AS [p] ON [o0].[ProductID] = [p].[ProductID] - WHERE ([p].[ProductName] = N'Chai') AND [p].[ProductName] IS NOT NULL + WHERE [p].[ProductName] = N'Chai' )"); } @@ -3678,7 +3617,7 @@ public override async Task Anonymous_complex_distinct_where(bool isAsync) AssertSql( @"SELECT DISTINCT [c].[CustomerID] + [c].[City] AS [A] FROM [Customers] AS [c] -WHERE (([c].[CustomerID] + [c].[City]) = N'ALFKIBerlin') AND [c].[City] IS NOT NULL"); +WHERE ([c].[CustomerID] + [c].[City]) = N'ALFKIBerlin'"); } public override async Task Anonymous_complex_distinct_orderby(bool isAsync) @@ -3725,17 +3664,17 @@ public override async Task Anonymous_subquery_orderby(bool isAsync) @"SELECT ( SELECT TOP(1) [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID] DESC) AS [A] FROM [Customers] AS [c] WHERE ( SELECT COUNT(*) FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL) > 1 + WHERE [c].[CustomerID] = [o0].[CustomerID]) > 1 ORDER BY ( SELECT TOP(1) [o1].[OrderDate] FROM [Orders] AS [o1] - WHERE ([c].[CustomerID] = [o1].[CustomerID]) AND [o1].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o1].[CustomerID] ORDER BY [o1].[OrderID] DESC)"); } @@ -3782,7 +3721,7 @@ public override async Task DTO_complex_distinct_where(bool isAsync) AssertSql( @"SELECT DISTINCT [c].[CustomerID] + [c].[City] AS [Property] FROM [Customers] AS [c] -WHERE (([c].[CustomerID] + [c].[City]) = N'ALFKIBerlin') AND [c].[City] IS NOT NULL"); +WHERE ([c].[CustomerID] + [c].[City]) = N'ALFKIBerlin'"); } public override async Task DTO_complex_distinct_orderby(bool isAsync) @@ -3830,17 +3769,17 @@ public override async Task DTO_subquery_orderby(bool isAsync) @"SELECT ( SELECT TOP(1) [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID] DESC) AS [Property] FROM [Customers] AS [c] WHERE ( SELECT COUNT(*) FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL) > 1 + WHERE [c].[CustomerID] = [o0].[CustomerID]) > 1 ORDER BY ( SELECT TOP(1) [o1].[OrderDate] FROM [Orders] AS [o1] - WHERE ([c].[CustomerID] = [o1].[CustomerID]) AND [o1].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o1].[CustomerID] ORDER BY [o1].[OrderID] DESC)"); } @@ -3884,7 +3823,7 @@ FROM [Customers] AS [c] WHERE ( SELECT TOP(1) [o].[CustomerID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID] DESC) IS NULL"); } @@ -3898,7 +3837,7 @@ FROM [Customers] AS [c] WHERE ( SELECT TOP(1) [o].[CustomerID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID] DESC) IS NOT NULL"); } @@ -4229,7 +4168,7 @@ public override async Task Comparing_to_fixed_string_parameter(bool isAsync) SELECT [c].[CustomerID] FROM [Customers] AS [c] -WHERE (@__prefix_0 = N'') OR ((LEFT([c].[CustomerID], LEN(@__prefix_0)) = @__prefix_0) AND LEFT([c].[CustomerID], LEN(@__prefix_0)) IS NOT NULL)"); +WHERE (@__prefix_0 = N'') OR (LEFT([c].[CustomerID], LEN(@__prefix_0)) = @__prefix_0)"); } public override async Task Comparing_entities_using_Equals(bool isAsync) @@ -4276,7 +4215,7 @@ FROM [Orders] AS [o] CROSS JOIN [Orders] AS [o0] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] LEFT JOIN [Customers] AS [c0] ON [o0].[CustomerID] = [c0].[CustomerID] -WHERE ([o].[CustomerID] IS NOT NULL AND ([o].[CustomerID] LIKE N'A%')) AND ((([c].[CustomerID] = [c0].[CustomerID]) AND ([c].[CustomerID] IS NOT NULL AND [c0].[CustomerID] IS NOT NULL)) OR ([c].[CustomerID] IS NULL AND [c0].[CustomerID] IS NULL)) +WHERE ([o].[CustomerID] IS NOT NULL AND ([o].[CustomerID] LIKE N'A%')) AND (([c].[CustomerID] = [c0].[CustomerID]) OR ([c].[CustomerID] IS NULL AND [c0].[CustomerID] IS NULL)) ORDER BY [o].[OrderID], [o0].[OrderID]"); } @@ -4290,7 +4229,7 @@ FROM [Orders] AS [o] CROSS JOIN [Orders] AS [o0] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] LEFT JOIN [Customers] AS [c0] ON [o0].[CustomerID] = [c0].[CustomerID] -WHERE ([o].[CustomerID] IS NOT NULL AND ([o].[CustomerID] LIKE N'A%')) AND ((([c].[CustomerID] = [c0].[CustomerID]) AND ([c].[CustomerID] IS NOT NULL AND [c0].[CustomerID] IS NOT NULL)) OR ([c].[CustomerID] IS NULL AND [c0].[CustomerID] IS NULL)) +WHERE ([o].[CustomerID] IS NOT NULL AND ([o].[CustomerID] LIKE N'A%')) AND (([c].[CustomerID] = [c0].[CustomerID]) OR ([c].[CustomerID] IS NULL AND [c0].[CustomerID] IS NULL)) ORDER BY [o].[OrderID], [o0].[OrderID]"); } @@ -4347,7 +4286,7 @@ public override async Task Compare_collection_navigation_with_itself(bool isAsyn AssertSql( @"SELECT [c].[CustomerID] FROM [Customers] AS [c] -WHERE ([c].[CustomerID] LIKE N'A%') AND ([c].[CustomerID] = [c].[CustomerID])"); +WHERE [c].[CustomerID] LIKE N'A%'"); } public override async Task Compare_two_collection_navigations_with_different_query_sources(bool isAsync) @@ -4419,9 +4358,9 @@ OUTER APPLY ( SELECT ( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AS [c], [c].[CustomerID], [o0].[OrderID] + WHERE [c].[CustomerID] = [o].[CustomerID]) AS [c], [c].[CustomerID], [o0].[OrderID] FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o0].[CustomerID] ) AS [t] WHERE [c].[CustomerID] = N'ALFKI' ORDER BY [c].[CustomerID], [t].[OrderID]"); @@ -4435,10 +4374,10 @@ public override async Task Complex_nested_query_properly_binds_to_grandparent_wh @"SELECT [c].[CustomerID], ( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND (( + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND (( SELECT COUNT(*) FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL) > 0)) AS [OuterOrders] + WHERE [c].[CustomerID] = [o0].[CustomerID]) > 0)) AS [OuterOrders] FROM [Customers] AS [c] WHERE [c].[CustomerID] = N'ALFKI'"); } @@ -4554,13 +4493,13 @@ public override async Task Let_entity_equality_to_null(bool isAsync) @"SELECT [c].[CustomerID], ( SELECT TOP(1) [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderDate]) AS [OrderDate] FROM [Customers] AS [c] WHERE ([c].[CustomerID] LIKE N'A%') AND ( SELECT TOP(1) [o0].[OrderID] FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o0].[CustomerID] ORDER BY [o0].[OrderDate]) IS NOT NULL"); } @@ -4572,17 +4511,17 @@ public override async Task Let_entity_equality_to_other_entity(bool isAsync) @"SELECT [c].[CustomerID], ( SELECT TOP(1) [o].[OrderDate] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderDate]) AS [A] FROM [Customers] AS [c] WHERE ([c].[CustomerID] LIKE N'A%') AND ((( SELECT TOP(1) [o0].[OrderID] FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o0].[CustomerID] ORDER BY [o0].[OrderDate]) <> 0) OR ( SELECT TOP(1) [o0].[OrderID] FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o0].[CustomerID] ORDER BY [o0].[OrderDate]) IS NULL)"); } @@ -4596,7 +4535,7 @@ FROM [Customers] AS [c] WHERE ( SELECT TOP(1) [o].[OrderID] FROM [Orders] AS [o] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID]) IS NULL"); } @@ -4611,7 +4550,7 @@ FROM [Customers] AS [c] SELECT TOP(1) [c0].[CustomerID] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c0] ON [o].[CustomerID] = [c0].[CustomerID] - WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + WHERE [c].[CustomerID] = [o].[CustomerID] ORDER BY [o].[OrderID]) IS NULL"); } @@ -4646,7 +4585,7 @@ FROM [Customers] AS [c] WHERE ( SELECT COUNT(*) FROM [Orders] AS [o] - WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL)) > 0"); + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND ([c].[CustomerID] = [o].[CustomerID])) > 0"); } public override async Task Convert_to_nullable_on_nullable_value_is_ignored(bool isAsync) @@ -4693,7 +4632,7 @@ FROM [Customers] AS [c] OUTER APPLY ( SELECT TOP(1) [o].[OrderDate], [o].[OrderID] FROM [Orders] AS [o] - WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND ((DATEPART(year, [o].[OrderDate]) = 1998) AND DATEPART(year, [o].[OrderDate]) IS NOT NULL) + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND (DATEPART(year, [o].[OrderDate]) = 1998) ORDER BY [o].[OrderID] ) AS [t] ORDER BY [c].[CustomerID], [t].[OrderID]"); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeographyTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeographyTest.cs index 31469c60041..d8e9c687da7 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeographyTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeographyTest.cs @@ -326,7 +326,7 @@ public override async Task GetInteriorRingN(bool isAsync) AssertSql( @"SELECT [p].[Id], CASE - WHEN [p].[Polygon] IS NULL OR ((([p].[Polygon].NumRings() - 1) = 0) AND [p].[Polygon].NumRings() IS NOT NULL) THEN NULL + WHEN [p].[Polygon] IS NULL OR (([p].[Polygon].NumRings() - 1) = 0) THEN NULL ELSE [p].[Polygon].RingN(0 + 2) END AS [InteriorRing0] FROM [PolygonEntity] AS [p]"); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeometryTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeometryTest.cs index 8bc8862f664..a2f9f4ae20f 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeometryTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SpatialQuerySqlServerGeometryTest.cs @@ -366,7 +366,7 @@ public override async Task GetInteriorRingN(bool isAsync) AssertSql( @"SELECT [p].[Id], CASE - WHEN [p].[Polygon] IS NULL OR (([p].[Polygon].STNumInteriorRing() = 0) AND [p].[Polygon].STNumInteriorRing() IS NOT NULL) THEN NULL + WHEN [p].[Polygon] IS NULL OR ([p].[Polygon].STNumInteriorRing() = 0) THEN NULL ELSE [p].[Polygon].STInteriorRingN(0 + 1) END AS [InteriorRing0] FROM [PolygonEntity] AS [p]"); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs b/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs index 88a2abe95d5..1533e0164e0 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs @@ -28,7 +28,7 @@ public override void Scalar_Function_Extension_Method_Static() AssertSql( @"SELECT COUNT(*) FROM [Customers] AS [c] -WHERE (IsDate([c].[FirstName]) = CAST(0 AS bit)) AND IsDate([c].[FirstName]) IS NOT NULL"); +WHERE IsDate([c].[FirstName]) = CAST(0 AS bit)"); } public override void Scalar_Function_With_Translator_Translates_Static() @@ -118,7 +118,7 @@ public override void Scalar_Function_Where_Not_Correlated_Static() SELECT TOP(2) [c].[Id] FROM [Customers] AS [c] -WHERE ([dbo].[GetCustomerWithMostOrdersAfterDate](@__startDate_0) = [c].[Id]) AND [dbo].[GetCustomerWithMostOrdersAfterDate](@__startDate_0) IS NOT NULL"); +WHERE [dbo].[GetCustomerWithMostOrdersAfterDate](@__startDate_0) = [c].[Id]"); } public override void Scalar_Function_Where_Parameter_Static() @@ -130,7 +130,7 @@ public override void Scalar_Function_Where_Parameter_Static() SELECT TOP(2) [c].[Id] FROM [Customers] AS [c] -WHERE ([c].[Id] = [dbo].[GetCustomerWithMostOrdersAfterDate]([dbo].[GetReportingPeriodStartDate](@__period_0))) AND [dbo].[GetCustomerWithMostOrdersAfterDate]([dbo].[GetReportingPeriodStartDate](@__period_0)) IS NOT NULL"); +WHERE [c].[Id] = [dbo].[GetCustomerWithMostOrdersAfterDate]([dbo].[GetReportingPeriodStartDate](@__period_0))"); } public override void Scalar_Function_Where_Nested_Static() @@ -226,7 +226,7 @@ public override void Scalar_Function_SqlFragment_Static() AssertSql( @"SELECT COUNT(*) FROM [Customers] AS [c] -WHERE ([c].[LastName] = 'Two') AND [c].[LastName] IS NOT NULL"); +WHERE [c].[LastName] = 'Two'"); } #endregion @@ -250,7 +250,7 @@ public override void Scalar_Function_Extension_Method_Instance() AssertSql( @"SELECT COUNT(*) FROM [Customers] AS [c] -WHERE (IsDate([c].[FirstName]) = CAST(0 AS bit)) AND IsDate([c].[FirstName]) IS NOT NULL"); +WHERE IsDate([c].[FirstName]) = CAST(0 AS bit)"); } public override void Scalar_Function_With_Translator_Translates_Instance() @@ -340,7 +340,7 @@ public override void Scalar_Function_Where_Not_Correlated_Instance() SELECT TOP(2) [c].[Id] FROM [Customers] AS [c] -WHERE ([dbo].[GetCustomerWithMostOrdersAfterDate](@__startDate_1) = [c].[Id]) AND [dbo].[GetCustomerWithMostOrdersAfterDate](@__startDate_1) IS NOT NULL"); +WHERE [dbo].[GetCustomerWithMostOrdersAfterDate](@__startDate_1) = [c].[Id]"); } public override void Scalar_Function_Where_Parameter_Instance() @@ -352,7 +352,7 @@ public override void Scalar_Function_Where_Parameter_Instance() SELECT TOP(2) [c].[Id] FROM [Customers] AS [c] -WHERE ([c].[Id] = [dbo].[GetCustomerWithMostOrdersAfterDate]([dbo].[GetReportingPeriodStartDate](@__period_1))) AND [dbo].[GetCustomerWithMostOrdersAfterDate]([dbo].[GetReportingPeriodStartDate](@__period_1)) IS NOT NULL"); +WHERE [c].[Id] = [dbo].[GetCustomerWithMostOrdersAfterDate]([dbo].[GetReportingPeriodStartDate](@__period_1))"); } public override void Scalar_Function_Where_Nested_Instance() diff --git a/test/EFCore.SqlServer.FunctionalTests/UpdatesSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/UpdatesSqlServerTest.cs index 2a0f029dd44..d3a9b3579aa 100644 --- a/test/EFCore.SqlServer.FunctionalTests/UpdatesSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/UpdatesSqlServerTest.cs @@ -30,7 +30,7 @@ public override void Save_replaced_principal() SELECT [p].[Id], [p].[DependentId], [p].[Name], [p].[Price] FROM [Products] AS [p] -WHERE ([p].[DependentId] = @__category_PrincipalId_0) AND [p].[DependentId] IS NOT NULL", +WHERE [p].[DependentId] = @__category_PrincipalId_0", // @"@p1='78' @p0='New Category' (Size = 4000) @@ -47,7 +47,7 @@ FROM [Products] AS [p] SELECT [p].[Id], [p].[DependentId], [p].[Name], [p].[Price] FROM [Products] AS [p] -WHERE ([p].[DependentId] = @__category_PrincipalId_0) AND [p].[DependentId] IS NOT NULL"); +WHERE [p].[DependentId] = @__category_PrincipalId_0"); } public override void Identifiers_are_generated_correctly() diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/FiltersSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/FiltersSqliteTest.cs index ba24ce01649..3a516633f18 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/FiltersSqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/FiltersSqliteTest.cs @@ -23,7 +23,7 @@ public override void Count_query() SELECT COUNT(*) FROM ""Customers"" AS ""c"" -WHERE (@__ef_filter__TenantPrefix_0 = '') OR (""c"".""CompanyName"" IS NOT NULL AND (((""c"".""CompanyName"" LIKE ""c"".""CompanyName"" || '%') AND ((substr(""c"".""CompanyName"", 1, length(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0) AND substr(""c"".""CompanyName"", 1, length(@__ef_filter__TenantPrefix_0)) IS NOT NULL)) OR (@__ef_filter__TenantPrefix_0 = '')))"); +WHERE (@__ef_filter__TenantPrefix_0 = '') OR (""c"".""CompanyName"" IS NOT NULL AND (((""c"".""CompanyName"" LIKE ""c"".""CompanyName"" || '%') AND (substr(""c"".""CompanyName"", 1, length(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0)) OR (@__ef_filter__TenantPrefix_0 = '')))"); } private void AssertSql(params string[] expected) diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/SimpleQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/SimpleQuerySqliteTest.cs index 3f3411cf3bc..cc1eb21be33 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/SimpleQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/SimpleQuerySqliteTest.cs @@ -449,7 +449,7 @@ public override async Task Where_datetime_now(bool isAsync) SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE rtrim(rtrim(strftime('%Y-%m-%d %H:%M:%f', 'now', 'localtime'), '0'), '.') <> @__myDatetime_0"); +WHERE (rtrim(rtrim(strftime('%Y-%m-%d %H:%M:%f', 'now', 'localtime'), '0'), '.') <> @__myDatetime_0) OR rtrim(rtrim(strftime('%Y-%m-%d %H:%M:%f', 'now', 'localtime'), '0'), '.') IS NULL"); } public override async Task Where_datetime_utcnow(bool isAsync) @@ -461,7 +461,7 @@ public override async Task Where_datetime_utcnow(bool isAsync) SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE rtrim(rtrim(strftime('%Y-%m-%d %H:%M:%f', 'now'), '0'), '.') <> @__myDatetime_0"); +WHERE (rtrim(rtrim(strftime('%Y-%m-%d %H:%M:%f', 'now'), '0'), '.') <> @__myDatetime_0) OR rtrim(rtrim(strftime('%Y-%m-%d %H:%M:%f', 'now'), '0'), '.') IS NULL"); } public override async Task Where_datetime_today(bool isAsync) @@ -471,7 +471,7 @@ public override async Task Where_datetime_today(bool isAsync) AssertSql( @"SELECT ""e"".""EmployeeID"", ""e"".""City"", ""e"".""Country"", ""e"".""FirstName"", ""e"".""ReportsTo"", ""e"".""Title"" FROM ""Employees"" AS ""e"" -WHERE rtrim(rtrim(strftime('%Y-%m-%d %H:%M:%f', 'now', 'localtime', 'start of day'), '0'), '.') = rtrim(rtrim(strftime('%Y-%m-%d %H:%M:%f', 'now', 'localtime', 'start of day'), '0'), '.')"); +WHERE (rtrim(rtrim(strftime('%Y-%m-%d %H:%M:%f', 'now', 'localtime', 'start of day'), '0'), '.') = rtrim(rtrim(strftime('%Y-%m-%d %H:%M:%f', 'now', 'localtime', 'start of day'), '0'), '.')) OR rtrim(rtrim(strftime('%Y-%m-%d %H:%M:%f', 'now', 'localtime', 'start of day'), '0'), '.') IS NULL"); } public override async Task Where_datetime_date_component(bool isAsync) @@ -483,7 +483,7 @@ public override async Task Where_datetime_date_component(bool isAsync) SELECT ""o"".""OrderID"", ""o"".""CustomerID"", ""o"".""EmployeeID"", ""o"".""OrderDate"" FROM ""Orders"" AS ""o"" -WHERE (rtrim(rtrim(strftime('%Y-%m-%d %H:%M:%f', ""o"".""OrderDate"", 'start of day'), '0'), '.') = @__myDatetime_0) AND rtrim(rtrim(strftime('%Y-%m-%d %H:%M:%f', ""o"".""OrderDate"", 'start of day'), '0'), '.') IS NOT NULL"); +WHERE rtrim(rtrim(strftime('%Y-%m-%d %H:%M:%f', ""o"".""OrderDate"", 'start of day'), '0'), '.') = @__myDatetime_0"); } public override async Task Where_datetime_year_component(bool isAsync) @@ -493,7 +493,7 @@ public override async Task Where_datetime_year_component(bool isAsync) AssertSql( @"SELECT ""o"".""OrderID"", ""o"".""CustomerID"", ""o"".""EmployeeID"", ""o"".""OrderDate"" FROM ""Orders"" AS ""o"" -WHERE (CAST(strftime('%Y', ""o"".""OrderDate"") AS INTEGER) = 1998) AND strftime('%Y', ""o"".""OrderDate"") IS NOT NULL"); +WHERE CAST(strftime('%Y', ""o"".""OrderDate"") AS INTEGER) = 1998"); } public override async Task Where_datetime_month_component(bool isAsync) @@ -503,7 +503,7 @@ public override async Task Where_datetime_month_component(bool isAsync) AssertSql( @"SELECT ""o"".""OrderID"", ""o"".""CustomerID"", ""o"".""EmployeeID"", ""o"".""OrderDate"" FROM ""Orders"" AS ""o"" -WHERE (CAST(strftime('%m', ""o"".""OrderDate"") AS INTEGER) = 4) AND strftime('%m', ""o"".""OrderDate"") IS NOT NULL"); +WHERE CAST(strftime('%m', ""o"".""OrderDate"") AS INTEGER) = 4"); } public override async Task Where_datetime_dayOfYear_component(bool isAsync) @@ -513,7 +513,7 @@ public override async Task Where_datetime_dayOfYear_component(bool isAsync) AssertSql( @"SELECT ""o"".""OrderID"", ""o"".""CustomerID"", ""o"".""EmployeeID"", ""o"".""OrderDate"" FROM ""Orders"" AS ""o"" -WHERE (CAST(strftime('%j', ""o"".""OrderDate"") AS INTEGER) = 68) AND strftime('%j', ""o"".""OrderDate"") IS NOT NULL"); +WHERE CAST(strftime('%j', ""o"".""OrderDate"") AS INTEGER) = 68"); } public override async Task Where_datetime_day_component(bool isAsync) @@ -523,7 +523,7 @@ public override async Task Where_datetime_day_component(bool isAsync) AssertSql( @"SELECT ""o"".""OrderID"", ""o"".""CustomerID"", ""o"".""EmployeeID"", ""o"".""OrderDate"" FROM ""Orders"" AS ""o"" -WHERE (CAST(strftime('%d', ""o"".""OrderDate"") AS INTEGER) = 4) AND strftime('%d', ""o"".""OrderDate"") IS NOT NULL"); +WHERE CAST(strftime('%d', ""o"".""OrderDate"") AS INTEGER) = 4"); } public override async Task Where_datetime_hour_component(bool isAsync) @@ -533,7 +533,7 @@ public override async Task Where_datetime_hour_component(bool isAsync) AssertSql( @"SELECT ""o"".""OrderID"", ""o"".""CustomerID"", ""o"".""EmployeeID"", ""o"".""OrderDate"" FROM ""Orders"" AS ""o"" -WHERE (CAST(strftime('%H', ""o"".""OrderDate"") AS INTEGER) = 14) AND strftime('%H', ""o"".""OrderDate"") IS NOT NULL"); +WHERE CAST(strftime('%H', ""o"".""OrderDate"") AS INTEGER) = 14"); } public override async Task Where_datetime_minute_component(bool isAsync) @@ -543,7 +543,7 @@ public override async Task Where_datetime_minute_component(bool isAsync) AssertSql( @"SELECT ""o"".""OrderID"", ""o"".""CustomerID"", ""o"".""EmployeeID"", ""o"".""OrderDate"" FROM ""Orders"" AS ""o"" -WHERE (CAST(strftime('%M', ""o"".""OrderDate"") AS INTEGER) = 23) AND strftime('%M', ""o"".""OrderDate"") IS NOT NULL"); +WHERE CAST(strftime('%M', ""o"".""OrderDate"") AS INTEGER) = 23"); } public override async Task Where_datetime_second_component(bool isAsync) @@ -553,7 +553,7 @@ public override async Task Where_datetime_second_component(bool isAsync) AssertSql( @"SELECT ""o"".""OrderID"", ""o"".""CustomerID"", ""o"".""EmployeeID"", ""o"".""OrderDate"" FROM ""Orders"" AS ""o"" -WHERE (CAST(strftime('%S', ""o"".""OrderDate"") AS INTEGER) = 44) AND strftime('%S', ""o"".""OrderDate"") IS NOT NULL"); +WHERE CAST(strftime('%S', ""o"".""OrderDate"") AS INTEGER) = 44"); } [ConditionalTheory(Skip = "Issue#15586")] @@ -584,7 +584,7 @@ public override async Task String_StartsWith_Identity(bool isAsync) AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE ((""c"".""ContactName"" = '') AND ""c"".""ContactName"" IS NOT NULL) OR (""c"".""ContactName"" IS NOT NULL AND (((""c"".""ContactName"" LIKE ""c"".""ContactName"" || '%') AND (substr(""c"".""ContactName"", 1, length(""c"".""ContactName"")) = ""c"".""ContactName"")) OR (""c"".""ContactName"" = '')))"); +WHERE (""c"".""ContactName"" = '') OR (""c"".""ContactName"" IS NOT NULL AND (""c"".""ContactName"" IS NOT NULL AND (((""c"".""ContactName"" LIKE ""c"".""ContactName"" || '%') AND (substr(""c"".""ContactName"", 1, length(""c"".""ContactName"")) = ""c"".""ContactName"")) OR (""c"".""ContactName"" = ''))))"); } public override async Task String_StartsWith_Column(bool isAsync) @@ -594,7 +594,7 @@ public override async Task String_StartsWith_Column(bool isAsync) AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE ((""c"".""ContactName"" = '') AND ""c"".""ContactName"" IS NOT NULL) OR (""c"".""ContactName"" IS NOT NULL AND (((""c"".""ContactName"" LIKE ""c"".""ContactName"" || '%') AND (substr(""c"".""ContactName"", 1, length(""c"".""ContactName"")) = ""c"".""ContactName"")) OR (""c"".""ContactName"" = '')))"); +WHERE (""c"".""ContactName"" = '') OR (""c"".""ContactName"" IS NOT NULL AND (""c"".""ContactName"" IS NOT NULL AND (((""c"".""ContactName"" LIKE ""c"".""ContactName"" || '%') AND (substr(""c"".""ContactName"", 1, length(""c"".""ContactName"")) = ""c"".""ContactName"")) OR (""c"".""ContactName"" = ''))))"); } public override async Task String_StartsWith_MethodCall(bool isAsync) @@ -624,7 +624,7 @@ public override async Task String_EndsWith_Identity(bool isAsync) AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE ((""c"".""ContactName"" = '') AND ""c"".""ContactName"" IS NOT NULL) OR (""c"".""ContactName"" IS NOT NULL AND ((substr(""c"".""ContactName"", -length(""c"".""ContactName"")) = ""c"".""ContactName"") OR (""c"".""ContactName"" = '')))"); +WHERE (""c"".""ContactName"" = '') OR (""c"".""ContactName"" IS NOT NULL AND (""c"".""ContactName"" IS NOT NULL AND ((substr(""c"".""ContactName"", -length(""c"".""ContactName"")) = ""c"".""ContactName"") OR (""c"".""ContactName"" = ''))))"); } public override async Task String_EndsWith_Column(bool isAsync) @@ -634,7 +634,7 @@ public override async Task String_EndsWith_Column(bool isAsync) AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE ((""c"".""ContactName"" = '') AND ""c"".""ContactName"" IS NOT NULL) OR (""c"".""ContactName"" IS NOT NULL AND ((substr(""c"".""ContactName"", -length(""c"".""ContactName"")) = ""c"".""ContactName"") OR (""c"".""ContactName"" = '')))"); +WHERE (""c"".""ContactName"" = '') OR (""c"".""ContactName"" IS NOT NULL AND (""c"".""ContactName"" IS NOT NULL AND ((substr(""c"".""ContactName"", -length(""c"".""ContactName"")) = ""c"".""ContactName"") OR (""c"".""ContactName"" = ''))))"); } public override async Task String_EndsWith_MethodCall(bool isAsync) @@ -664,7 +664,7 @@ public override async Task String_Contains_Identity(bool isAsync) AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE ((""c"".""ContactName"" = '') AND ""c"".""ContactName"" IS NOT NULL) OR (instr(""c"".""ContactName"", ""c"".""ContactName"") > 0)"); +WHERE (""c"".""ContactName"" = '') OR (instr(""c"".""ContactName"", ""c"".""ContactName"") > 0)"); } public override async Task String_Contains_Column(bool isAsync) @@ -674,7 +674,7 @@ public override async Task String_Contains_Column(bool isAsync) AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE ((""c"".""ContactName"" = '') AND ""c"".""ContactName"" IS NOT NULL) OR (instr(""c"".""ContactName"", ""c"".""ContactName"") > 0)"); +WHERE (""c"".""ContactName"" = '') OR (instr(""c"".""ContactName"", ""c"".""ContactName"") > 0)"); } public override async Task String_Contains_MethodCall(bool isAsync) @@ -694,7 +694,7 @@ public override async Task IsNullOrWhiteSpace_in_predicate(bool isAsync) AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE ""c"".""Region"" IS NULL OR ((trim(""c"".""Region"") = '') AND trim(""c"".""Region"") IS NOT NULL)"); +WHERE ""c"".""Region"" IS NULL OR (trim(""c"".""Region"") = '')"); } public override async Task Where_string_length(bool isAsync) @@ -704,7 +704,7 @@ public override async Task Where_string_length(bool isAsync) AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE (length(""c"".""City"") = 6) AND length(""c"".""City"") IS NOT NULL"); +WHERE length(""c"".""City"") = 6"); } public override async Task Where_string_indexof(bool isAsync) @@ -734,7 +734,7 @@ public override async Task Where_string_replace(bool isAsync) AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE (replace(""c"".""City"", 'Sea', 'Rea') = 'Reattle') AND replace(""c"".""City"", 'Sea', 'Rea') IS NOT NULL"); +WHERE replace(""c"".""City"", 'Sea', 'Rea') = 'Reattle'"); } public override async Task Replace_with_emptystring(bool isAsync) @@ -754,7 +754,7 @@ public override async Task Where_string_substring(bool isAsync) AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE (substr(""c"".""City"", 1 + 1, 2) = 'ea') AND substr(""c"".""City"", 1 + 1, 2) IS NOT NULL"); +WHERE substr(""c"".""City"", 1 + 1, 2) = 'ea'"); } public override async Task Substring_with_zero_startindex(bool isAsync) @@ -896,7 +896,7 @@ public override async Task TrimStart_without_arguments_in_predicate(bool isAsync AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE (ltrim(""c"".""ContactTitle"") = 'Owner') AND ltrim(""c"".""ContactTitle"") IS NOT NULL"); +WHERE ltrim(""c"".""ContactTitle"") = 'Owner'"); } public override async Task TrimStart_with_char_argument_in_predicate(bool isAsync) @@ -906,7 +906,7 @@ public override async Task TrimStart_with_char_argument_in_predicate(bool isAsyn AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE (ltrim(""c"".""ContactTitle"", 'O') = 'wner') AND ltrim(""c"".""ContactTitle"", 'O') IS NOT NULL"); +WHERE ltrim(""c"".""ContactTitle"", 'O') = 'wner'"); } public override async Task TrimStart_with_char_array_argument_in_predicate(bool isAsync) @@ -916,7 +916,7 @@ public override async Task TrimStart_with_char_array_argument_in_predicate(bool AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE (ltrim(""c"".""ContactTitle"", 'Ow') = 'ner') AND ltrim(""c"".""ContactTitle"", 'Ow') IS NOT NULL"); +WHERE ltrim(""c"".""ContactTitle"", 'Ow') = 'ner'"); } public override async Task TrimEnd_without_arguments_in_predicate(bool isAsync) @@ -926,7 +926,7 @@ public override async Task TrimEnd_without_arguments_in_predicate(bool isAsync) AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE (rtrim(""c"".""ContactTitle"") = 'Owner') AND rtrim(""c"".""ContactTitle"") IS NOT NULL"); +WHERE rtrim(""c"".""ContactTitle"") = 'Owner'"); } public override async Task TrimEnd_with_char_argument_in_predicate(bool isAsync) @@ -936,7 +936,7 @@ public override async Task TrimEnd_with_char_argument_in_predicate(bool isAsync) AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE (rtrim(""c"".""ContactTitle"", 'r') = 'Owne') AND rtrim(""c"".""ContactTitle"", 'r') IS NOT NULL"); +WHERE rtrim(""c"".""ContactTitle"", 'r') = 'Owne'"); } public override async Task TrimEnd_with_char_array_argument_in_predicate(bool isAsync) @@ -946,7 +946,7 @@ public override async Task TrimEnd_with_char_array_argument_in_predicate(bool is AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE (rtrim(""c"".""ContactTitle"", 'er') = 'Own') AND rtrim(""c"".""ContactTitle"", 'er') IS NOT NULL"); +WHERE rtrim(""c"".""ContactTitle"", 'er') = 'Own'"); } public override async Task Trim_without_argument_in_predicate(bool isAsync) @@ -956,7 +956,7 @@ public override async Task Trim_without_argument_in_predicate(bool isAsync) AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE (trim(""c"".""ContactTitle"") = 'Owner') AND trim(""c"".""ContactTitle"") IS NOT NULL"); +WHERE trim(""c"".""ContactTitle"") = 'Owner'"); } public override async Task Trim_with_char_argument_in_predicate(bool isAsync) @@ -966,7 +966,7 @@ public override async Task Trim_with_char_argument_in_predicate(bool isAsync) AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE (trim(""c"".""ContactTitle"", 'O') = 'wner') AND trim(""c"".""ContactTitle"", 'O') IS NOT NULL"); +WHERE trim(""c"".""ContactTitle"", 'O') = 'wner'"); } public override async Task Trim_with_char_array_argument_in_predicate(bool isAsync) @@ -976,7 +976,7 @@ public override async Task Trim_with_char_array_argument_in_predicate(bool isAsy AssertSql( @"SELECT ""c"".""CustomerID"", ""c"".""Address"", ""c"".""City"", ""c"".""CompanyName"", ""c"".""ContactName"", ""c"".""ContactTitle"", ""c"".""Country"", ""c"".""Fax"", ""c"".""Phone"", ""c"".""PostalCode"", ""c"".""Region"" FROM ""Customers"" AS ""c"" -WHERE (trim(""c"".""ContactTitle"", 'Or') = 'wne') AND trim(""c"".""ContactTitle"", 'Or') IS NOT NULL"); +WHERE trim(""c"".""ContactTitle"", 'Or') = 'wne'"); } public override async Task Select_datetime_year_component(bool isAsync) From 70c898882c9add74f0c0b6a928772a7a26396189 Mon Sep 17 00:00:00 2001 From: AndriySvyryd Date: Thu, 31 Oct 2019 09:08:06 -0700 Subject: [PATCH 4/4] Add back execution retry for query. Move the retry scope for SaveChanges to properly reset the state before retrying. Fixes #18628 --- All.sln.DotSettings | 6 +- .../RelationalDatabaseFacadeExtensions.cs | 4 + .../Migrations/HistoryRepository.cs | 10 +- .../Migrations/Internal/Migrator.cs | 2 + .../Migrations/MigrationCommand.cs | 2 + .../Query/Internal/BufferedDataReader.cs | 1324 +++++++++++++++++ .../Query/Internal/QueryingEnumerable.cs | 148 +- ...dQueryCompilingExpressionVisitorFactory.cs | 4 +- .../Query/QuerySqlGenerator.cs | 4 +- ...elationalCompiledQueryCacheKeyGenerator.cs | 17 +- .../Query/RelationalQueryContext.cs | 9 - .../RelationalQueryContextDependencies.cs | 6 + ...jectionBindingRemovingExpressionVisitor.cs | 65 +- ...alShapedQueryCompilingExpressionVisitor.cs | 42 +- src/EFCore.Relational/Storage/ReaderColumn.cs | 52 + .../Storage/ReaderColumn`.cs | 29 + .../Storage/RelationalCommand.cs | 21 +- .../RelationalCommandParameterObject.cs | 8 + .../Storage/RelationalTypeMapping.cs | 12 +- .../Update/Internal/BatchExecutor.cs | 23 +- .../Update/ReaderModificationCommandBatch.cs | 2 + ...SqlServerCompiledQueryCacheKeyGenerator.cs | 4 +- .../Internal/SqlServerDatabaseCreator.cs | 4 + .../SqlServerSequenceHiLoValueGenerator.cs | 10 +- .../Storage/Internal/SqliteDatabaseCreator.cs | 2 + .../ChangeTracking/Internal/StateManager.cs | 135 +- .../Internal/StateManagerDependencies.cs | 48 + ...piledQueryCacheKeyGeneratorDependencies.cs | 36 +- ...ingExpressionVisitor.ExpressionVisitors.cs | 6 +- src/EFCore/Query/QueryCompilationContext.cs | 2 + .../QueryCompilationContextDependencies.cs | 37 + src/EFCore/Query/QueryContext.cs | 9 + src/EFCore/Query/QueryContextDependencies.cs | 24 +- .../ShapedQueryCompilingExpressionVisitor.cs | 3 + .../Storage/ExecutionStrategyExtensions.cs | 32 +- ...tegy.cs => TestCosmosExecutionStrategy.cs} | 1 + .../CommandInterceptionTestBase.cs | 41 +- .../Query/AsyncFromSqlQueryTestBase.cs | 56 +- .../Query/FromSqlQueryTestBase.cs | 142 +- .../Query/FromSqlSprocQueryTestBase.cs | 12 +- .../Query/GearsOfWarFromSqlQueryTestBase.cs | 10 +- .../Query/InheritanceRelationalTestBase.cs | 12 +- .../Query/NullSemanticsQueryTestBase.cs | 8 +- .../Query/QueryNoClientEvalTestBase.cs | 8 +- .../RelationalDatabaseCleaner.cs | 2 +- .../TestUtilities/RelationalTestStore.cs | 12 +- .../Query/Internal/BufferedDataReaderTest.cs | 217 +++ .../Storage/RelationalCommandTest.cs | 30 +- .../FakeProvider/FakeDbDataReader.cs | 42 +- .../InterceptionTestBase.cs | 2 +- .../TestUtilities/DataGenerator.cs | 47 + .../TestUtilities/TestHelpers.cs | 2 +- .../CommandInterceptionSqlServerTest.cs | 16 + .../ExecutionStrategyTest.cs | 348 +++-- .../Query/AsyncSimpleQuerySqlServerTest.cs | 20 +- .../TestSqlServerRetryingExecutionStrategy.cs | 4 +- ...SqlServerRetryingExecutionStrategyTests.cs | 9 +- ...dQueryCacheKeyGeneratorDependenciesTest.cs | 1 + ...QueryCompilationContextDependenciesTest.cs | 1 + .../Storage/ExecutionStrategyTest.cs | 12 +- 60 files changed, 2626 insertions(+), 571 deletions(-) create mode 100644 src/EFCore.Relational/Query/Internal/BufferedDataReader.cs create mode 100644 src/EFCore.Relational/Storage/ReaderColumn.cs create mode 100644 src/EFCore.Relational/Storage/ReaderColumn`.cs rename test/EFCore.Cosmos.FunctionalTests/TestUtilities/{TestSqlServerRetryingExecutionStrategy.cs => TestCosmosExecutionStrategy.cs} (96%) create mode 100644 test/EFCore.Relational.Tests/Query/Internal/BufferedDataReaderTest.cs create mode 100644 test/EFCore.Specification.Tests/TestUtilities/DataGenerator.cs diff --git a/All.sln.DotSettings b/All.sln.DotSettings index ea433c87d71..af1c1434b20 100644 --- a/All.sln.DotSettings +++ b/All.sln.DotSettings @@ -198,6 +198,7 @@ Licensed under the Apache License, Version 2.0. See License.txt in the project r True True True + True True True True @@ -207,10 +208,13 @@ Licensed under the Apache License, Version 2.0. See License.txt in the project r True True True + True True True + True True True True True - True \ No newline at end of file + True + True \ No newline at end of file diff --git a/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs b/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs index b85fe09aa52..3b73238aadd 100644 --- a/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs @@ -222,6 +222,7 @@ public static int ExecuteSqlCommand( new RelationalCommandParameterObject( GetFacadeDependencies(databaseFacade).RelationalConnection, rawSqlCommand.ParameterValues, + null, ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context, logger)); } @@ -388,6 +389,7 @@ public static async Task ExecuteSqlCommandAsync( new RelationalCommandParameterObject( facadeDependencies.RelationalConnection, rawSqlCommand.ParameterValues, + null, ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context, logger), cancellationToken); @@ -504,6 +506,7 @@ public static int ExecuteSqlRaw( new RelationalCommandParameterObject( facadeDependencies.RelationalConnection, rawSqlCommand.ParameterValues, + null, ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context, logger)); } @@ -656,6 +659,7 @@ public static async Task ExecuteSqlRawAsync( new RelationalCommandParameterObject( facadeDependencies.RelationalConnection, rawSqlCommand.ParameterValues, + null, ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context, logger), cancellationToken); diff --git a/src/EFCore.Relational/Migrations/HistoryRepository.cs b/src/EFCore.Relational/Migrations/HistoryRepository.cs index bd6a27a0503..b9da13008e7 100644 --- a/src/EFCore.Relational/Migrations/HistoryRepository.cs +++ b/src/EFCore.Relational/Migrations/HistoryRepository.cs @@ -127,7 +127,7 @@ protected virtual string ProductVersionColumnName /// /// Checks whether or not the history table exists. /// - /// True if the table already exists, false otherwise. + /// true if the table already exists, false otherwise. public virtual bool Exists() => Dependencies.DatabaseCreator.Exists() && InterpretExistsResult( @@ -135,6 +135,7 @@ public virtual bool Exists() new RelationalCommandParameterObject( Dependencies.Connection, null, + null, Dependencies.CurrentContext.Context, Dependencies.CommandLogger))); @@ -144,7 +145,7 @@ public virtual bool Exists() /// A to observe while waiting for the task to complete. /// /// A task that represents the asynchronous operation. The task result contains - /// True if the table already exists, false otherwise. + /// true if the table already exists, false otherwise. /// public virtual async Task ExistsAsync(CancellationToken cancellationToken = default) => await Dependencies.DatabaseCreator.ExistsAsync(cancellationToken) @@ -153,6 +154,7 @@ await Dependencies.RawSqlCommandBuilder.Build(ExistsSql).ExecuteScalarAsync( new RelationalCommandParameterObject( Dependencies.Connection, null, + null, Dependencies.CurrentContext.Context, Dependencies.CommandLogger), cancellationToken)); @@ -160,7 +162,7 @@ await Dependencies.RawSqlCommandBuilder.Build(ExistsSql).ExecuteScalarAsync( /// /// Interprets the result of executing . /// - /// true if the table exists; otherwise, false. + /// true if the table already exists, false otherwise. protected abstract bool InterpretExistsResult([NotNull] object value); /// @@ -217,6 +219,7 @@ public virtual IReadOnlyList GetAppliedMigrations() new RelationalCommandParameterObject( Dependencies.Connection, null, + null, Dependencies.CurrentContext.Context, Dependencies.CommandLogger))) { @@ -251,6 +254,7 @@ public virtual async Task> GetAppliedMigrationsAsync( new RelationalCommandParameterObject( Dependencies.Connection, null, + null, Dependencies.CurrentContext.Context, Dependencies.CommandLogger), cancellationToken)) diff --git a/src/EFCore.Relational/Migrations/Internal/Migrator.cs b/src/EFCore.Relational/Migrations/Internal/Migrator.cs index 9593c458905..f8dc7514f7d 100644 --- a/src/EFCore.Relational/Migrations/Internal/Migrator.cs +++ b/src/EFCore.Relational/Migrations/Internal/Migrator.cs @@ -117,6 +117,7 @@ public virtual void Migrate(string targetMigration = null) new RelationalCommandParameterObject( _connection, null, + null, _currentContext.Context, _commandLogger)); } @@ -154,6 +155,7 @@ await command.ExecuteNonQueryAsync( new RelationalCommandParameterObject( _connection, null, + null, _currentContext.Context, _commandLogger), cancellationToken); diff --git a/src/EFCore.Relational/Migrations/MigrationCommand.cs b/src/EFCore.Relational/Migrations/MigrationCommand.cs index ddd4a65dfc2..a3d3d98c45d 100644 --- a/src/EFCore.Relational/Migrations/MigrationCommand.cs +++ b/src/EFCore.Relational/Migrations/MigrationCommand.cs @@ -64,6 +64,7 @@ public virtual int ExecuteNonQuery( new RelationalCommandParameterObject( connection, parameterValues, + null, _context, _logger)); @@ -82,6 +83,7 @@ public virtual Task ExecuteNonQueryAsync( new RelationalCommandParameterObject( connection, parameterValues, + null, _context, _logger), cancellationToken); diff --git a/src/EFCore.Relational/Query/Internal/BufferedDataReader.cs b/src/EFCore.Relational/Query/Internal/BufferedDataReader.cs new file mode 100644 index 00000000000..1b2e25ac33f --- /dev/null +++ b/src/EFCore.Relational/Query/Internal/BufferedDataReader.cs @@ -0,0 +1,1324 @@ +// 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; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Utilities; + +namespace Microsoft.EntityFrameworkCore.Query.Internal +{ + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public class BufferedDataReader : DbDataReader + { + private DbDataReader _underlyingReader; + private List _bufferedDataRecords = new List(); + private BufferedDataRecord _currentResultSet; + private int _currentResultSetNumber; + private int _recordsAffected; + private bool _disposed; + private bool _isClosed; + + public BufferedDataReader([NotNull] DbDataReader reader) + { + _underlyingReader = reader; + } + + public override int RecordsAffected => _recordsAffected; + + public override object this[string name] => throw new NotSupportedException(); + + public override object this[int ordinal] => throw new NotSupportedException(); + + public override int Depth => throw new NotSupportedException(); + + public override int FieldCount + { + get + { + AssertReaderIsOpen(); + return _currentResultSet.FieldCount; + } + } + + public override bool HasRows + { + get + { + AssertReaderIsOpen(); + return _currentResultSet.HasRows; + } + } + + public override bool IsClosed => _isClosed; + + [Conditional("DEBUG")] + private void AssertReaderIsOpen() + { + if (_underlyingReader != null) + { + throw new InvalidOperationException("The reader wasn't initialized"); + } + + if (_isClosed) + { + throw new InvalidOperationException("The reader is closed."); + } + } + + [Conditional("DEBUG")] + private void AssertReaderIsOpenWithData() + { + AssertReaderIsOpen(); + + if (!_currentResultSet.IsDataReady) + { + throw new InvalidOperationException("The reader doesn't have any data."); + } + } + + [Conditional("DEBUG")] + private void AssertFieldIsReady(int ordinal) + { + AssertReaderIsOpenWithData(); + + if (0 > ordinal + || ordinal > _currentResultSet.FieldCount) + { + throw new IndexOutOfRangeException(); + } + } + + public virtual BufferedDataReader Initialize([NotNull] IReadOnlyList columns) + { + if (_underlyingReader == null) + { + return this; + } + + try + { + do + { + _bufferedDataRecords.Add(new BufferedDataRecord().Initialize(_underlyingReader, columns)); + } + while (_underlyingReader.NextResult()); + + _recordsAffected = _underlyingReader.RecordsAffected; + _currentResultSet = _bufferedDataRecords[_currentResultSetNumber]; + + return this; + } + finally + { + _underlyingReader.Dispose(); + _underlyingReader = null; + } + } + + public virtual async Task InitializeAsync( + [NotNull] IReadOnlyList columns, CancellationToken cancellationToken) + { + if (_underlyingReader == null) + { + return this; + } + + try + { + do + { + _bufferedDataRecords.Add(await new BufferedDataRecord().InitializeAsync(_underlyingReader, columns, cancellationToken)); + } + while (await _underlyingReader.NextResultAsync(cancellationToken)); + + _recordsAffected = _underlyingReader.RecordsAffected; + _currentResultSet = _bufferedDataRecords[_currentResultSetNumber]; + + return this; + } + finally + { + _underlyingReader.Dispose(); + _underlyingReader = null; + } + } + + public static bool IsSupportedValueType(Type type) + => type == typeof(int) + || type == typeof(bool) + || type == typeof(Guid) + || type == typeof(byte) + || type == typeof(char) + || type == typeof(DateTime) + || type == typeof(DateTimeOffset) + || type == typeof(decimal) + || type == typeof(double) + || type == typeof(float) + || type == typeof(short) + || type == typeof(long) + || type == typeof(uint) + || type == typeof(ushort) + || type == typeof(ulong) + || type == typeof(sbyte); + + public override void Close() + { + _bufferedDataRecords = null; + _isClosed = true; + + var reader = _underlyingReader; + if (reader != null) + { + _underlyingReader = null; + reader.Dispose(); + } + } + + protected override void Dispose(bool disposing) + { + if (!_disposed + && disposing + && !IsClosed) + { + Close(); + } + + _disposed = true; + + base.Dispose(disposing); + } + + public override bool GetBoolean(int ordinal) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.GetBoolean(ordinal); + } + + public override byte GetByte(int ordinal) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.GetByte(ordinal); + } + + public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length) + { + throw new NotSupportedException(); + } + + public override char GetChar(int ordinal) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.GetChar(ordinal); + } + + public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) + { + throw new NotSupportedException(); + } + + public override DateTime GetDateTime(int ordinal) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.GetDateTime(ordinal); + } + + public override decimal GetDecimal(int ordinal) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.GetDecimal(ordinal); + } + + public override double GetDouble(int ordinal) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.GetDouble(ordinal); + } + + public override float GetFloat(int ordinal) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.GetFloat(ordinal); + } + + public override Guid GetGuid(int ordinal) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.GetGuid(ordinal); + } + + public override short GetInt16(int ordinal) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.GetInt16(ordinal); + } + + public override int GetInt32(int ordinal) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.GetInt32(ordinal); + } + + public override long GetInt64(int ordinal) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.GetInt64(ordinal); + } + + public override string GetString(int ordinal) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.GetFieldValue(ordinal); + } + + public override T GetFieldValue(int ordinal) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.GetFieldValue(ordinal); + } + + public override Task GetFieldValueAsync(int ordinal, CancellationToken cancellationToken) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.GetFieldValueAsync(ordinal, cancellationToken); + } + + public override object GetValue(int ordinal) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.GetValue(ordinal); + } + + public override int GetValues(object[] values) + { + AssertReaderIsOpenWithData(); + return _currentResultSet.GetValues(values); + } + + public override string GetDataTypeName(int ordinal) + { + AssertReaderIsOpen(); + return _currentResultSet.GetDataTypeName(ordinal); + } + + public override Type GetFieldType(int ordinal) + { + AssertReaderIsOpen(); + return _currentResultSet.GetFieldType(ordinal); + } + + public override string GetName(int ordinal) + { + AssertReaderIsOpen(); + return _currentResultSet.GetName(ordinal); + } + + public override int GetOrdinal(string name) + { + Check.NotNull(name, "name"); + AssertReaderIsOpen(); + return _currentResultSet.GetOrdinal(name); + } + + public override bool IsDBNull(int ordinal) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.IsDBNull(ordinal); + } + + public override Task IsDBNullAsync(int ordinal, CancellationToken cancellationToken) + { + AssertFieldIsReady(ordinal); + return _currentResultSet.IsDBNullAsync(ordinal, cancellationToken); + } + + public override IEnumerator GetEnumerator() => throw new NotSupportedException(); + + public override DataTable GetSchemaTable() => throw new NotSupportedException(); + + public override bool NextResult() + { + AssertReaderIsOpen(); + if (++_currentResultSetNumber < _bufferedDataRecords.Count) + { + _currentResultSet = _bufferedDataRecords[_currentResultSetNumber]; + return true; + } + + _currentResultSet = null; + return false; + } + + public override Task NextResultAsync(CancellationToken cancellationToken) + => Task.FromResult(NextResult()); + + public override bool Read() + { + AssertReaderIsOpen(); + return _currentResultSet.Read(); + } + + public override Task ReadAsync(CancellationToken cancellationToken) + { + AssertReaderIsOpen(); + return _currentResultSet.ReadAsync(cancellationToken); + } + + private class BufferedDataRecord + { + private int _currentRowNumber = -1; + private int _rowCount; + private string[] _dataTypeNames; + private Type[] _fieldTypes; + private string[] _columnNames; + private Lazy> _fieldNameLookup; + + private int _rowCapacity = 1; + + // Resizing bool[] is faster than BitArray, but the latter is more efficient for long-term storage. + private BitArray _bools; + private bool[] _tempBools; + private int _boolCount; + private byte[] _bytes; + private int _byteCount; + private char[] _chars; + private int _charCount; + private DateTime[] _dateTimes; + private int _dateTimeCount; + private DateTimeOffset[] _dateTimeOffsets; + private int _dateTimeOffsetCount; + private decimal[] _decimals; + private int _decimalCount; + private double[] _doubles; + private int _doubleCount; + private float[] _floats; + private int _floatCount; + private Guid[] _guids; + private int _guidCount; + private short[] _shorts; + private int _shortCount; + private int[] _ints; + private int _intCount; + private long[] _longs; + private int _longCount; + private sbyte[] _sbytes; + private int _sbyteCount; + private uint[] _uints; + private int _uintCount; + private ushort[] _ushorts; + private int _ushortCount; + private ulong[] _ulongs; + private int _ulongCount; + private object[] _objects; + private int _objectCount; + private int[] _ordinalToIndexMap; + + private BitArray _nulls; + private bool[] _tempNulls; + private int _nullCount; + private int[] _nullOrdinalToIndexMap; + + private TypeCase[] _columnTypeCases; + + private DbDataReader _underlyingReader; + private IReadOnlyList _columns; + private int[] _indexMap; + + public bool IsDataReady { get; private set; } + + public bool HasRows => _rowCount > 0; + + public int FieldCount => _fieldTypes.Length; + + public string GetDataTypeName(int ordinal) => _dataTypeNames[ordinal]; + + public Type GetFieldType(int ordinal) => _fieldTypes[ordinal]; + + public string GetName(int ordinal) => _columnNames[ordinal]; + + public int GetOrdinal(string name) => _fieldNameLookup.Value[name]; + + public bool GetBoolean(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.Bool + ? _bools[_currentRowNumber * _boolCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public byte GetByte(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.Byte + ? _bytes[_currentRowNumber * _byteCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public char GetChar(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.Char + ? _chars[_currentRowNumber * _charCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public DateTime GetDateTime(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.DateTime + ? _dateTimes[_currentRowNumber * _dateTimeCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public DateTimeOffset GetDateTimeOffset(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.DateTimeOffset + ? _dateTimeOffsets[_currentRowNumber * _dateTimeOffsetCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public decimal GetDecimal(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.Decimal + ? _decimals[_currentRowNumber * _decimalCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public double GetDouble(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.Double + ? _doubles[_currentRowNumber * _doubleCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public float GetFloat(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.Float + ? _floats[_currentRowNumber * _floatCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public Guid GetGuid(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.Guid + ? _guids[_currentRowNumber * _guidCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public short GetInt16(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.Short + ? _shorts[_currentRowNumber * _shortCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public int GetInt32(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.Int + ? _ints[_currentRowNumber * _intCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public long GetInt64(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.Long + ? _longs[_currentRowNumber * _longCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public sbyte GetSByte(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.SByte + ? _sbytes[_currentRowNumber * _sbyteCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public ushort GetUInt16(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.UShort + ? _ushorts[_currentRowNumber * _ushortCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public uint GetUInt32(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.UInt + ? _uints[_currentRowNumber * _uintCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public ulong GetUInt64(int ordinal) + => _columnTypeCases[ordinal] == TypeCase.ULong + ? _ulongs[_currentRowNumber * _ulongCount + _ordinalToIndexMap[ordinal]] + : GetFieldValue(ordinal); + + public object GetValue(int ordinal) + => GetFieldValue(ordinal); + + public int GetValues(object[] values) + => throw new NotSupportedException(); + + public T GetFieldValue(int ordinal) + { + switch (_columnTypeCases[ordinal]) + { + case TypeCase.Bool: + return (T)(object)GetBoolean(ordinal); + case TypeCase.Byte: + return (T)(object)GetByte(ordinal); + case TypeCase.Char: + return (T)(object)GetChar(ordinal); + case TypeCase.DateTime: + return (T)(object)GetDateTime(ordinal); + case TypeCase.DateTimeOffset: + return (T)(object)GetDateTimeOffset(ordinal); + case TypeCase.Decimal: + return (T)(object)GetDecimal(ordinal); + case TypeCase.Double: + return (T)(object)GetDouble(ordinal); + case TypeCase.Float: + return (T)(object)GetFloat(ordinal); + case TypeCase.Guid: + return (T)(object)GetGuid(ordinal); + case TypeCase.Short: + return (T)(object)GetInt16(ordinal); + case TypeCase.Int: + return (T)(object)GetInt32(ordinal); + case TypeCase.Long: + return (T)(object)GetInt64(ordinal); + case TypeCase.SByte: + return (T)(object)GetSByte(ordinal); + case TypeCase.UShort: + return (T)(object)GetUInt16(ordinal); + case TypeCase.UInt: + return (T)(object)GetUInt32(ordinal); + case TypeCase.ULong: + return (T)(object)GetUInt64(ordinal); + case TypeCase.Empty: + return default; + default: + return (T)_objects[_currentRowNumber * _objectCount + _ordinalToIndexMap[ordinal]]; + } + } + + public Task GetFieldValueAsync(int ordinal, CancellationToken cancellationToken) + => Task.FromResult(GetFieldValue(ordinal)); + + public bool IsDBNull(int ordinal) => _nulls[_currentRowNumber * _nullCount + _nullOrdinalToIndexMap[ordinal]]; + + public Task IsDBNullAsync(int ordinal, CancellationToken cancellationToken) => Task.FromResult(IsDBNull(ordinal)); + + public bool Read() => IsDataReady = ++_currentRowNumber < _rowCount; + + public Task ReadAsync(CancellationToken cancellationToken) => Task.FromResult(Read()); + + public BufferedDataRecord Initialize([NotNull] DbDataReader reader, [NotNull] IReadOnlyList columns) + { + _underlyingReader = reader; + _columns = columns; + + ReadMetadata(); + InitializeFields(); + + while (reader.Read()) + { + ReadRow(); + } + + _bools = new BitArray(_tempBools); + _tempBools = null; + _nulls = new BitArray(_tempNulls); + _tempNulls = null; + _rowCount = _currentRowNumber + 1; + _currentRowNumber = -1; + _underlyingReader = null; + _columns = null; + + return this; + } + + public async Task InitializeAsync( + [NotNull] DbDataReader reader, [NotNull] IReadOnlyList columns, CancellationToken cancellationToken) + { + _underlyingReader = reader; + _columns = columns; + + ReadMetadata(); + InitializeFields(); + + while (await reader.ReadAsync(cancellationToken)) + { + ReadRow(); + } + + _bools = new BitArray(_tempBools); + _tempBools = null; + _nulls = new BitArray(_tempNulls); + _tempNulls = null; + _rowCount = _currentRowNumber + 1; + _currentRowNumber = -1; + _underlyingReader = null; + _columns = null; + + return this; + } + + private void ReadRow() + { + _currentRowNumber++; + + if (_rowCapacity == _currentRowNumber) + { + DoubleBufferCapacity(); + } + + for (var i = 0; i < FieldCount; i++) + { + var column = _columns[i]; + var nullIndex = _nullOrdinalToIndexMap[i]; + switch (_columnTypeCases[i]) + { + case TypeCase.Bool: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadBool(_underlyingReader, i, column); + } + } + else + { + ReadBool(_underlyingReader, i, column); + } + + break; + case TypeCase.Byte: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadByte(_underlyingReader, i, column); + } + } + else + { + ReadByte(_underlyingReader, i, column); + } + + break; + case TypeCase.Char: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadChar(_underlyingReader, i, column); + } + } + else + { + ReadChar(_underlyingReader, i, column); + } + + break; + case TypeCase.DateTime: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadDateTime(_underlyingReader, i, column); + } + } + else + { + ReadDateTime(_underlyingReader, i, column); + } + + break; + case TypeCase.DateTimeOffset: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadDateTimeOffset(_underlyingReader, i, column); + } + } + else + { + ReadDateTimeOffset(_underlyingReader, i, column); + } + + break; + case TypeCase.Decimal: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadDecimal(_underlyingReader, i, column); + } + } + else + { + ReadDecimal(_underlyingReader, i, column); + } + + break; + case TypeCase.Double: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadDouble(_underlyingReader, i, column); + } + } + else + { + ReadDouble(_underlyingReader, i, column); + } + + break; + case TypeCase.Float: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadFloat(_underlyingReader, i, column); + } + } + else + { + ReadFloat(_underlyingReader, i, column); + } + + break; + case TypeCase.Guid: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadGuid(_underlyingReader, i, column); + } + } + else + { + ReadGuid(_underlyingReader, i, column); + } + + break; + case TypeCase.Short: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadShort(_underlyingReader, i, column); + } + } + else + { + ReadShort(_underlyingReader, i, column); + } + + break; + case TypeCase.Int: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadInt(_underlyingReader, i, column); + } + } + else + { + ReadInt(_underlyingReader, i, column); + } + + break; + case TypeCase.Long: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadLong(_underlyingReader, i, column); + } + } + else + { + ReadLong(_underlyingReader, i, column); + } + + break; + case TypeCase.SByte: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadSByte(_underlyingReader, i, column); + } + } + else + { + ReadSByte(_underlyingReader, i, column); + } + + break; + case TypeCase.UShort: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadUShort(_underlyingReader, i, column); + } + } + else + { + ReadUShort(_underlyingReader, i, column); + } + + break; + case TypeCase.UInt: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadUInt(_underlyingReader, i, column); + } + } + else + { + ReadUInt(_underlyingReader, i, column); + } + + break; + case TypeCase.ULong: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadULong(_underlyingReader, i, column); + } + } + else + { + ReadULong(_underlyingReader, i, column); + } + + break; + case TypeCase.Empty: + break; + default: + if (nullIndex != -1) + { + if (!(_tempNulls[_currentRowNumber * _nullCount + nullIndex] = _underlyingReader.IsDBNull(i))) + { + ReadObject(_underlyingReader, i, column); + } + } + else + { + ReadObject(_underlyingReader, i, column); + } + + break; + } + } + } + + private void ReadMetadata() + { + var fieldCount = _underlyingReader.FieldCount; + var dataTypeNames = new string[fieldCount]; + var columnTypes = new Type[fieldCount]; + var columnNames = new string[fieldCount]; + for (var i = 0; i < fieldCount; i++) + { + dataTypeNames[i] = _underlyingReader.GetDataTypeName(i); + columnTypes[i] = _underlyingReader.GetFieldType(i); + columnNames[i] = _underlyingReader.GetName(i); + } + + _dataTypeNames = dataTypeNames; + _fieldTypes = columnTypes; + _columnNames = columnNames; + _fieldNameLookup = new Lazy>(CreateNameLookup, isThreadSafe: false); + + Dictionary CreateNameLookup() + { + var index = new Dictionary(StringComparer.OrdinalIgnoreCase); + for (var i = 0; i < _columnNames.Length; i++) + { + index[_columnNames[i]] = i; + } + + return index; + } + } + + private void InitializeFields() + { + var fieldCount = FieldCount; + if (FieldCount < _columns.Count) + { + throw new InvalidOperationException("The underlying reader doesn't have as many fields as expected."); + } + + _columnTypeCases = Enumerable.Repeat(TypeCase.Empty, fieldCount).ToArray(); + _ordinalToIndexMap = Enumerable.Repeat(-1, fieldCount).ToArray(); + if (_columns.Count > 0 + && _columns[0].Name != null) + { + // Non-Composed FromSql + var readerColumns = _fieldNameLookup.Value; + + _indexMap = new int[_columns.Count]; + var newColumnMap = new ReaderColumn[fieldCount]; + for (var i = 0; i < _columns.Count; i++) + { + var column = _columns[i]; + if (!readerColumns.TryGetValue(column.Name, out var ordinal)) + { + throw new InvalidOperationException(RelationalStrings.FromSqlMissingColumn(column.Name)); + } + + newColumnMap[ordinal] = column; + _indexMap[i] = ordinal; + } + + _columns = newColumnMap; + } + + if (FieldCount != _columns.Count) + { + var newColumnMap = new ReaderColumn[fieldCount]; + for (var i = 0; i < _columns.Count; i++) + { + newColumnMap[i] = _columns[i]; + } + _columns = newColumnMap; + } + + for (var i = 0; i < fieldCount; i++) + { + var column = _columns[i]; + if (column == null) + { + continue; + } + + var type = column.Type; + if (type == typeof(bool)) + { + _columnTypeCases[i] = TypeCase.Bool; + _ordinalToIndexMap[i] = _boolCount; + _boolCount++; + } + else if (type == typeof(byte)) + { + _columnTypeCases[i] = TypeCase.Byte; + _ordinalToIndexMap[i] = _byteCount; + _byteCount++; + } + else if (type == typeof(char)) + { + _columnTypeCases[i] = TypeCase.Char; + _ordinalToIndexMap[i] = _charCount; + _charCount++; + } + else if (type == typeof(DateTime)) + { + _columnTypeCases[i] = TypeCase.DateTime; + _ordinalToIndexMap[i] = _dateTimeCount; + _dateTimeCount++; + } + else if (type == typeof(DateTimeOffset)) + { + _columnTypeCases[i] = TypeCase.DateTimeOffset; + _ordinalToIndexMap[i] = _dateTimeOffsetCount; + _dateTimeOffsetCount++; + } + else if (type == typeof(decimal)) + { + _columnTypeCases[i] = TypeCase.Decimal; + _ordinalToIndexMap[i] = _decimalCount; + _decimalCount++; + } + else if (type == typeof(double)) + { + _columnTypeCases[i] = TypeCase.Double; + _ordinalToIndexMap[i] = _doubleCount; + _doubleCount++; + } + else if (type == typeof(float)) + { + _columnTypeCases[i] = TypeCase.Float; + _ordinalToIndexMap[i] = _floatCount; + _floatCount++; + } + else if (type == typeof(Guid)) + { + _columnTypeCases[i] = TypeCase.Guid; + _ordinalToIndexMap[i] = _guidCount; + _guidCount++; + } + else if (type == typeof(short)) + { + _columnTypeCases[i] = TypeCase.Short; + _ordinalToIndexMap[i] = _shortCount; + _shortCount++; + } + else if (type == typeof(int)) + { + _columnTypeCases[i] = TypeCase.Int; + _ordinalToIndexMap[i] = _intCount; + _intCount++; + } + else if (type == typeof(long)) + { + _columnTypeCases[i] = TypeCase.Long; + _ordinalToIndexMap[i] = _longCount; + _longCount++; + } + else if (type == typeof(sbyte)) + { + _columnTypeCases[i] = TypeCase.SByte; + _ordinalToIndexMap[i] = _sbyteCount; + _sbyteCount++; + } + else if (type == typeof(ushort)) + { + _columnTypeCases[i] = TypeCase.UShort; + _ordinalToIndexMap[i] = _ushortCount; + _ushortCount++; + } + else if (type == typeof(uint)) + { + _columnTypeCases[i] = TypeCase.UInt; + _ordinalToIndexMap[i] = _uintCount; + _uintCount++; + } + else if (type == typeof(ulong)) + { + _columnTypeCases[i] = TypeCase.ULong; + _ordinalToIndexMap[i] = _ulongCount; + _ulongCount++; + } + else + { + _columnTypeCases[i] = TypeCase.Object; + _ordinalToIndexMap[i] = _objectCount; + _objectCount++; + } + } + + _tempBools = new bool[_rowCapacity * _boolCount]; + _bytes = new byte[_rowCapacity * _byteCount]; + _chars = new char[_rowCapacity * _charCount]; + _dateTimes = new DateTime[_rowCapacity * _dateTimeCount]; + _dateTimeOffsets = new DateTimeOffset[_rowCapacity * _dateTimeOffsetCount]; + _decimals = new decimal[_rowCapacity * _decimalCount]; + _doubles = new double[_rowCapacity * _doubleCount]; + _floats = new float[_rowCapacity * _floatCount]; + _guids = new Guid[_rowCapacity * _guidCount]; + _shorts = new short[_rowCapacity * _shortCount]; + _ints = new int[_rowCapacity * _intCount]; + _longs = new long[_rowCapacity * _longCount]; + _sbytes = new sbyte[_rowCapacity * _sbyteCount]; + _ushorts = new ushort[_rowCapacity * _ushortCount]; + _uints = new uint[_rowCapacity * _uintCount]; + _ulongs = new ulong[_rowCapacity * _ulongCount]; + _objects = new object[_rowCapacity * _objectCount]; + + _nullOrdinalToIndexMap = Enumerable.Repeat(-1, fieldCount).ToArray(); + for (var i = 0; i < fieldCount; i++) + { + if (_columns[i]?.IsNullable == true) + { + _nullOrdinalToIndexMap[i] = _nullCount; + _nullCount++; + } + } + + _tempNulls = new bool[_rowCapacity * _nullCount]; + } + + private void DoubleBufferCapacity() + { + _rowCapacity <<= 1; + + var newBools = new bool[_tempBools.Length << 1]; + Array.Copy(_tempBools, newBools, _tempBools.Length); + _tempBools = newBools; + + var newBytes = new byte[_bytes.Length << 1]; + Array.Copy(_bytes, newBytes, _bytes.Length); + _bytes = newBytes; + + var newChars = new char[_chars.Length << 1]; + Array.Copy(_chars, newChars, _chars.Length); + _chars = newChars; + + var newDateTimes = new DateTime[_dateTimes.Length << 1]; + Array.Copy(_dateTimes, newDateTimes, _dateTimes.Length); + _dateTimes = newDateTimes; + + var newDateTimeOffsets = new DateTimeOffset[_dateTimeOffsets.Length << 1]; + Array.Copy(_dateTimeOffsets, newDateTimeOffsets, _dateTimeOffsets.Length); + _dateTimeOffsets = newDateTimeOffsets; + + var newDecimals = new decimal[_decimals.Length << 1]; + Array.Copy(_decimals, newDecimals, _decimals.Length); + _decimals = newDecimals; + + var newDoubles = new double[_doubles.Length << 1]; + Array.Copy(_doubles, newDoubles, _doubles.Length); + _doubles = newDoubles; + + var newFloats = new float[_floats.Length << 1]; + Array.Copy(_floats, newFloats, _floats.Length); + _floats = newFloats; + + var newGuids = new Guid[_guids.Length << 1]; + Array.Copy(_guids, newGuids, _guids.Length); + _guids = newGuids; + + var newShorts = new short[_shorts.Length << 1]; + Array.Copy(_shorts, newShorts, _shorts.Length); + _shorts = newShorts; + + var newInts = new int[_ints.Length << 1]; + Array.Copy(_ints, newInts, _ints.Length); + _ints = newInts; + + var newLongs = new long[_longs.Length << 1]; + Array.Copy(_longs, newLongs, _longs.Length); + _longs = newLongs; + + var newSBytes = new sbyte[_sbytes.Length << 1]; + Array.Copy(_sbytes, newSBytes, _sbytes.Length); + _sbytes = newSBytes; + + var newUShorts = new ushort[_ushorts.Length << 1]; + Array.Copy(_ushorts, newUShorts, _ushorts.Length); + _ushorts = newUShorts; + + var newUInts = new uint[_uints.Length << 1]; + Array.Copy(_uints, newUInts, _uints.Length); + _uints = newUInts; + + var newULongs = new ulong[_ulongs.Length << 1]; + Array.Copy(_ulongs, newULongs, _ulongs.Length); + _ulongs = newULongs; + + var newObjects = new object[_objects.Length << 1]; + Array.Copy(_objects, newObjects, _objects.Length); + _objects = newObjects; + + var newNulls = new bool[_tempNulls.Length << 1]; + Array.Copy(_tempNulls, newNulls, _tempNulls.Length); + _tempNulls = newNulls; + } + + private void ReadBool(DbDataReader reader, int ordinal, ReaderColumn column) + { + _tempBools[_currentRowNumber * _boolCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadByte(DbDataReader reader, int ordinal, ReaderColumn column) + { + _bytes[_currentRowNumber * _byteCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadChar(DbDataReader reader, int ordinal, ReaderColumn column) + { + _chars[_currentRowNumber * _charCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadDateTime(DbDataReader reader, int ordinal, ReaderColumn column) + { + _dateTimes[_currentRowNumber * _dateTimeCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadDateTimeOffset(DbDataReader reader, int ordinal, ReaderColumn column) + { + _dateTimeOffsets[_currentRowNumber * _dateTimeOffsetCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadDecimal(DbDataReader reader, int ordinal, ReaderColumn column) + { + _decimals[_currentRowNumber * _decimalCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadDouble(DbDataReader reader, int ordinal, ReaderColumn column) + { + _doubles[_currentRowNumber * _doubleCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadFloat(DbDataReader reader, int ordinal, ReaderColumn column) + { + _floats[_currentRowNumber * _floatCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadGuid(DbDataReader reader, int ordinal, ReaderColumn column) + { + _guids[_currentRowNumber * _guidCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadShort(DbDataReader reader, int ordinal, ReaderColumn column) + { + _shorts[_currentRowNumber * _shortCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadInt(DbDataReader reader, int ordinal, ReaderColumn column) + { + _ints[_currentRowNumber * _intCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadLong(DbDataReader reader, int ordinal, ReaderColumn column) + { + _longs[_currentRowNumber * _longCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadSByte(DbDataReader reader, int ordinal, ReaderColumn column) + { + _sbytes[_currentRowNumber * _sbyteCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadUShort(DbDataReader reader, int ordinal, ReaderColumn column) + { + _ushorts[_currentRowNumber * _ushortCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadUInt(DbDataReader reader, int ordinal, ReaderColumn column) + { + _uints[_currentRowNumber * _uintCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadULong(DbDataReader reader, int ordinal, ReaderColumn column) + { + _ulongs[_currentRowNumber * _ulongCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private void ReadObject(DbDataReader reader, int ordinal, ReaderColumn column) + { + _objects[_currentRowNumber * _objectCount + _ordinalToIndexMap[ordinal]] = + ((ReaderColumn)column).GetFieldValue(reader, _indexMap); + } + + private enum TypeCase + { + Empty = 0, + Object, + Bool, + Byte, + Char, + DateTime, + DateTimeOffset, + Decimal, + Double, + Float, + Guid, + SByte, + Short, + Int, + Long, + UInt, + ULong, + UShort + } + } + } +} diff --git a/src/EFCore.Relational/Query/Internal/QueryingEnumerable.cs b/src/EFCore.Relational/Query/Internal/QueryingEnumerable.cs index fabb829eb93..4a58a8c7acb 100644 --- a/src/EFCore.Relational/Query/Internal/QueryingEnumerable.cs +++ b/src/EFCore.Relational/Query/Internal/QueryingEnumerable.cs @@ -24,6 +24,7 @@ public class QueryingEnumerable : IEnumerable, IAsyncEnumerable private readonly RelationalQueryContext _relationalQueryContext; private readonly RelationalCommandCache _relationalCommandCache; private readonly IReadOnlyList _columnNames; + private readonly IReadOnlyList _readerColumns; private readonly Func _shaper; private readonly Type _contextType; private readonly IDiagnosticsLogger _logger; @@ -32,6 +33,7 @@ public QueryingEnumerable( RelationalQueryContext relationalQueryContext, RelationalCommandCache relationalCommandCache, IReadOnlyList columnNames, + IReadOnlyList readerColumns, Func shaper, Type contextType, IDiagnosticsLogger logger) @@ -39,6 +41,7 @@ public QueryingEnumerable( _relationalQueryContext = relationalQueryContext; _relationalCommandCache = relationalCommandCache; _columnNames = columnNames; + _readerColumns = readerColumns; _shaper = shaper; _contextType = contextType; _logger = logger; @@ -50,11 +53,38 @@ public virtual IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancella public virtual IEnumerator GetEnumerator() => new Enumerator(this); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public static int[] BuildIndexMap(IReadOnlyList columnNames, DbDataReader dataReader) + { + if (columnNames == null) + { + return null; + } + + // Non-Composed FromSql + var readerColumns = Enumerable.Range(0, dataReader.FieldCount) + .ToDictionary(dataReader.GetName, i => i, StringComparer.OrdinalIgnoreCase); + + var indexMap = new int[columnNames.Count]; + for (var i = 0; i < columnNames.Count; i++) + { + var columnName = columnNames[i]; + if (!readerColumns.TryGetValue(columnName, out var ordinal)) + { + throw new InvalidOperationException(RelationalStrings.FromSqlMissingColumn(columnName)); + } + + indexMap[i] = ordinal; + } + + return indexMap; + } + private sealed class Enumerator : IEnumerator { private readonly RelationalQueryContext _relationalQueryContext; private readonly RelationalCommandCache _relationalCommandCache; private readonly IReadOnlyList _columnNames; + private readonly IReadOnlyList _readerColumns; private readonly Func _shaper; private readonly Type _contextType; private readonly IDiagnosticsLogger _logger; @@ -62,12 +92,14 @@ private sealed class Enumerator : IEnumerator private RelationalDataReader _dataReader; private int[] _indexMap; private ResultCoordinator _resultCoordinator; + private IExecutionStrategy _executionStrategy; public Enumerator(QueryingEnumerable queryingEnumerable) { _relationalQueryContext = queryingEnumerable._relationalQueryContext; _relationalCommandCache = queryingEnumerable._relationalCommandCache; _columnNames = queryingEnumerable._columnNames; + _readerColumns = queryingEnumerable._readerColumns; _shaper = queryingEnumerable._shaper; _contextType = queryingEnumerable._contextType; _logger = queryingEnumerable._logger; @@ -85,41 +117,12 @@ public bool MoveNext() { if (_dataReader == null) { - var relationalCommand = _relationalCommandCache.GetRelationalCommand( - _relationalQueryContext.ParameterValues); - - _dataReader - = relationalCommand.ExecuteReader( - new RelationalCommandParameterObject( - _relationalQueryContext.Connection, - _relationalQueryContext.ParameterValues, - _relationalQueryContext.Context, - _relationalQueryContext.CommandLogger)); - - // Non-Composed FromSql - if (_columnNames != null) - { - var readerColumns = Enumerable.Range(0, _dataReader.DbDataReader.FieldCount) - .ToDictionary(i => _dataReader.DbDataReader.GetName(i), i => i, StringComparer.OrdinalIgnoreCase); - - _indexMap = new int[_columnNames.Count]; - for (var i = 0; i < _columnNames.Count; i++) - { - var columnName = _columnNames[i]; - if (!readerColumns.TryGetValue(columnName, out var ordinal)) - { - throw new InvalidOperationException(RelationalStrings.FromSqlMissingColumn(columnName)); - } - - _indexMap[i] = ordinal; - } - } - else + if (_executionStrategy == null) { - _indexMap = null; + _executionStrategy = _relationalQueryContext.ExecutionStrategyFactory.Create(); } - _resultCoordinator = new ResultCoordinator(); + _executionStrategy.Execute(true, InitializeReader, null); } var hasNext = _resultCoordinator.HasNext ?? _dataReader.Read(); @@ -166,6 +169,26 @@ public bool MoveNext() } } + private bool InitializeReader(DbContext _, bool result) + { + var relationalCommand = _relationalCommandCache.GetRelationalCommand(_relationalQueryContext.ParameterValues); + + _dataReader + = relationalCommand.ExecuteReader( + new RelationalCommandParameterObject( + _relationalQueryContext.Connection, + _relationalQueryContext.ParameterValues, + _readerColumns, + _relationalQueryContext.Context, + _relationalQueryContext.CommandLogger)); + + _indexMap = BuildIndexMap(_columnNames, _dataReader.DbDataReader); + + _resultCoordinator = new ResultCoordinator(); + + return result; + } + public void Dispose() { _dataReader?.Dispose(); @@ -180,6 +203,7 @@ private sealed class AsyncEnumerator : IAsyncEnumerator private readonly RelationalQueryContext _relationalQueryContext; private readonly RelationalCommandCache _relationalCommandCache; private readonly IReadOnlyList _columnNames; + private readonly IReadOnlyList _readerColumns; private readonly Func _shaper; private readonly Type _contextType; private readonly IDiagnosticsLogger _logger; @@ -188,6 +212,7 @@ private sealed class AsyncEnumerator : IAsyncEnumerator private RelationalDataReader _dataReader; private int[] _indexMap; private ResultCoordinator _resultCoordinator; + private IExecutionStrategy _executionStrategy; public AsyncEnumerator( QueryingEnumerable queryingEnumerable, @@ -196,6 +221,7 @@ public AsyncEnumerator( _relationalQueryContext = queryingEnumerable._relationalQueryContext; _relationalCommandCache = queryingEnumerable._relationalCommandCache; _columnNames = queryingEnumerable._columnNames; + _readerColumns = queryingEnumerable._readerColumns; _shaper = queryingEnumerable._shaper; _contextType = queryingEnumerable._contextType; _logger = queryingEnumerable._logger; @@ -212,42 +238,12 @@ public async ValueTask MoveNextAsync() { if (_dataReader == null) { - var relationalCommand = _relationalCommandCache.GetRelationalCommand( - _relationalQueryContext.ParameterValues); - - _dataReader - = await relationalCommand.ExecuteReaderAsync( - new RelationalCommandParameterObject( - _relationalQueryContext.Connection, - _relationalQueryContext.ParameterValues, - _relationalQueryContext.Context, - _relationalQueryContext.CommandLogger), - _cancellationToken); - - // Non-Composed FromSql - if (_columnNames != null) + if (_executionStrategy == null) { - var readerColumns = Enumerable.Range(0, _dataReader.DbDataReader.FieldCount) - .ToDictionary(i => _dataReader.DbDataReader.GetName(i), i => i, StringComparer.OrdinalIgnoreCase); - - _indexMap = new int[_columnNames.Count]; - for (var i = 0; i < _columnNames.Count; i++) - { - var columnName = _columnNames[i]; - if (!readerColumns.TryGetValue(columnName, out var ordinal)) - { - throw new InvalidOperationException(RelationalStrings.FromSqlMissingColumn(columnName)); - } - - _indexMap[i] = ordinal; - } - } - else - { - _indexMap = null; + _executionStrategy = _relationalQueryContext.ExecutionStrategyFactory.Create(); } - _resultCoordinator = new ResultCoordinator(); + await _executionStrategy.ExecuteAsync(true, InitializeReaderAsync, null, _cancellationToken); } var hasNext = _resultCoordinator.HasNext ?? await _dataReader.ReadAsync(_cancellationToken); @@ -294,6 +290,28 @@ public async ValueTask MoveNextAsync() } } + private async Task InitializeReaderAsync(DbContext _, bool result, CancellationToken cancellationToken) + { + var relationalCommand = _relationalCommandCache.GetRelationalCommand( + _relationalQueryContext.ParameterValues); + + _dataReader + = await relationalCommand.ExecuteReaderAsync( + new RelationalCommandParameterObject( + _relationalQueryContext.Connection, + _relationalQueryContext.ParameterValues, + _readerColumns, + _relationalQueryContext.Context, + _relationalQueryContext.CommandLogger), + cancellationToken); + + _indexMap = BuildIndexMap(_columnNames, _dataReader.DbDataReader); + + _resultCoordinator = new ResultCoordinator(); + + return result; + } + public ValueTask DisposeAsync() { if (_dataReader != null) diff --git a/src/EFCore.Relational/Query/Internal/RelationalShapedQueryCompilingExpressionVisitorFactory.cs b/src/EFCore.Relational/Query/Internal/RelationalShapedQueryCompilingExpressionVisitorFactory.cs index 1dde1662282..b1db95792fb 100644 --- a/src/EFCore.Relational/Query/Internal/RelationalShapedQueryCompilingExpressionVisitorFactory.cs +++ b/src/EFCore.Relational/Query/Internal/RelationalShapedQueryCompilingExpressionVisitorFactory.cs @@ -29,11 +29,9 @@ public RelationalShapedQueryCompilingExpressionVisitorFactory( } public virtual ShapedQueryCompilingExpressionVisitor Create(QueryCompilationContext queryCompilationContext) - { - return new RelationalShapedQueryCompilingExpressionVisitor( + => new RelationalShapedQueryCompilingExpressionVisitor( _dependencies, _relationalDependencies, queryCompilationContext); - } } } diff --git a/src/EFCore.Relational/Query/QuerySqlGenerator.cs b/src/EFCore.Relational/Query/QuerySqlGenerator.cs index 3e6aba88f5d..4133df125a6 100644 --- a/src/EFCore.Relational/Query/QuerySqlGenerator.cs +++ b/src/EFCore.Relational/Query/QuerySqlGenerator.cs @@ -15,7 +15,7 @@ namespace Microsoft.EntityFrameworkCore.Query { public class QuerySqlGenerator : SqlExpressionVisitor { - private static readonly Regex _composibleSql + private static readonly Regex _composableSql = new Regex(@"^\s*?SELECT\b", RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(value: 1000.0)); private readonly IRelationalCommandBuilderFactory _relationalCommandBuilderFactory; @@ -319,7 +319,7 @@ protected override Expression VisitFromSql(FromSqlExpression fromSqlExpression) { _relationalCommandBuilder.AppendLine("("); - if (!_composibleSql.IsMatch(fromSqlExpression.Sql)) + if (!_composableSql.IsMatch(fromSqlExpression.Sql)) { throw new InvalidOperationException(RelationalStrings.FromSqlNonComposable); } diff --git a/src/EFCore.Relational/Query/RelationalCompiledQueryCacheKeyGenerator.cs b/src/EFCore.Relational/Query/RelationalCompiledQueryCacheKeyGenerator.cs index d1e1a8115ad..c2a4f3c5a2b 100644 --- a/src/EFCore.Relational/Query/RelationalCompiledQueryCacheKeyGenerator.cs +++ b/src/EFCore.Relational/Query/RelationalCompiledQueryCacheKeyGenerator.cs @@ -66,7 +66,8 @@ public override object GenerateCacheKey(Expression query, bool async) protected new RelationalCompiledQueryCacheKey GenerateCacheKeyCore([NotNull] Expression query, bool async) => new RelationalCompiledQueryCacheKey( base.GenerateCacheKeyCore(query, async), - RelationalOptionsExtension.Extract(RelationalDependencies.ContextOptions).UseRelationalNulls); + RelationalOptionsExtension.Extract(RelationalDependencies.ContextOptions).UseRelationalNulls, + shouldBuffer: Dependencies.IsRetryingExecutionStrategy); /// /// @@ -82,17 +83,20 @@ protected readonly struct RelationalCompiledQueryCacheKey { private readonly CompiledQueryCacheKey _compiledQueryCacheKey; private readonly bool _useRelationalNulls; + private readonly bool _shouldBuffer; /// /// Initializes a new instance of the class. /// /// The non-relational cache key. /// True to use relational null logic. + /// True if the query should be buffered. public RelationalCompiledQueryCacheKey( - CompiledQueryCacheKey compiledQueryCacheKey, bool useRelationalNulls) + CompiledQueryCacheKey compiledQueryCacheKey, bool useRelationalNulls, bool shouldBuffer) { _compiledQueryCacheKey = compiledQueryCacheKey; _useRelationalNulls = useRelationalNulls; + _shouldBuffer = shouldBuffer; } /// @@ -106,12 +110,13 @@ public RelationalCompiledQueryCacheKey( /// public override bool Equals(object obj) => !(obj is null) - && obj is RelationalCompiledQueryCacheKey - && Equals((RelationalCompiledQueryCacheKey)obj); + && obj is RelationalCompiledQueryCacheKey key + && Equals(key); private bool Equals(RelationalCompiledQueryCacheKey other) => _compiledQueryCacheKey.Equals(other._compiledQueryCacheKey) - && _useRelationalNulls == other._useRelationalNulls; + && _useRelationalNulls == other._useRelationalNulls + && _shouldBuffer == other._shouldBuffer; /// /// Gets the hash code for the key. @@ -119,7 +124,7 @@ private bool Equals(RelationalCompiledQueryCacheKey other) /// /// The hash code for the key. /// - public override int GetHashCode() => HashCode.Combine(_compiledQueryCacheKey, _useRelationalNulls); + public override int GetHashCode() => HashCode.Combine(_compiledQueryCacheKey, _useRelationalNulls, _shouldBuffer); } } } diff --git a/src/EFCore.Relational/Query/RelationalQueryContext.cs b/src/EFCore.Relational/Query/RelationalQueryContext.cs index 6601923169c..14ccb558bb1 100644 --- a/src/EFCore.Relational/Query/RelationalQueryContext.cs +++ b/src/EFCore.Relational/Query/RelationalQueryContext.cs @@ -46,14 +46,5 @@ public RelationalQueryContext( /// public virtual IRelationalConnection Connection => RelationalDependencies.RelationalConnection; - - /// - /// The execution strategy factory. - /// - /// - /// The execution strategy factory. - /// - public virtual IExecutionStrategyFactory ExecutionStrategyFactory - => RelationalDependencies.ExecutionStrategyFactory; } } diff --git a/src/EFCore.Relational/Query/RelationalQueryContextDependencies.cs b/src/EFCore.Relational/Query/RelationalQueryContextDependencies.cs index ed335407559..7ad601c4ca8 100644 --- a/src/EFCore.Relational/Query/RelationalQueryContextDependencies.cs +++ b/src/EFCore.Relational/Query/RelationalQueryContextDependencies.cs @@ -1,6 +1,7 @@ // 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 JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; @@ -62,7 +63,9 @@ public RelationalQueryContextDependencies( Check.NotNull(executionStrategyFactory, nameof(executionStrategyFactory)); RelationalConnection = relationalConnection; +#pragma warning disable 618 ExecutionStrategyFactory = executionStrategyFactory; +#pragma warning restore 618 } /// @@ -73,6 +76,7 @@ public RelationalQueryContextDependencies( /// /// The execution strategy. /// + [Obsolete("Moved to QueryContextDependencies")] public IExecutionStrategyFactory ExecutionStrategyFactory { get; } /// @@ -81,7 +85,9 @@ public RelationalQueryContextDependencies( /// A replacement for the current dependency of this type. /// A new parameter object with the given service replaced. public RelationalQueryContextDependencies With([NotNull] IRelationalConnection relationalConnection) +#pragma warning disable 618 => new RelationalQueryContextDependencies(relationalConnection, ExecutionStrategyFactory); +#pragma warning restore 618 /// /// Clones this dependency parameter object with one service replaced. diff --git a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.RelationalProjectionBindingRemovingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.RelationalProjectionBindingRemovingExpressionVisitor.cs index 03d90077a1f..e7eb6c00454 100644 --- a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.RelationalProjectionBindingRemovingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.RelationalProjectionBindingRemovingExpressionVisitor.cs @@ -9,6 +9,7 @@ using System.Reflection; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; using Microsoft.EntityFrameworkCore.Storage; @@ -23,15 +24,33 @@ private class RelationalProjectionBindingRemovingExpressionVisitor : ExpressionV private readonly SelectExpression _selectExpression; private readonly ParameterExpression _dbDataReaderParameter; + private readonly ParameterExpression _indexMapParameter; private readonly IDictionary> _materializationContextBindings = new Dictionary>(); public RelationalProjectionBindingRemovingExpressionVisitor( - SelectExpression selectExpression, ParameterExpression dbDataReaderParameter) + SelectExpression selectExpression, + ParameterExpression dbDataReaderParameter, + ParameterExpression indexMapParameter, + bool buffer) { _selectExpression = selectExpression; _dbDataReaderParameter = dbDataReaderParameter; + _indexMapParameter = indexMapParameter; + if (buffer) + { + ProjectionColumns = new ReaderColumn[selectExpression.Projection.Count]; + } + } + + private ReaderColumn[] ProjectionColumns { get; } + + public virtual Expression Visit(Expression node, out IReadOnlyList projectionColumns) + { + var result = Visit(node); + projectionColumns = ProjectionColumns; + return result; } protected override Expression VisitBinary(BinaryExpression binaryExpression) @@ -118,8 +137,8 @@ private object GetProjectionIndex(ProjectionBindingExpression projectionBindingE private static bool IsNullableProjection(ProjectionExpression projection) => !(projection.Expression is ColumnExpression column) || column.IsNullable; - private static Expression CreateGetValueExpression( - Expression dbDataReader, + private Expression CreateGetValueExpression( + ParameterExpression dbDataReader, int index, bool nullable, RelationalTypeMapping typeMapping, @@ -127,16 +146,52 @@ private static Expression CreateGetValueExpression( { var getMethod = typeMapping.GetDataReaderMethod(); - var indexExpression = Expression.Constant(index); + Expression indexExpression = Expression.Constant(index); + if (_indexMapParameter != null) + { + indexExpression = Expression.ArrayIndex(_indexMapParameter, indexExpression); + } Expression valueExpression = Expression.Call( getMethod.DeclaringType != typeof(DbDataReader) ? Expression.Convert(dbDataReader, getMethod.DeclaringType) - : dbDataReader, + : (Expression)dbDataReader, getMethod, indexExpression); + if (ProjectionColumns != null) + { + var columnType = valueExpression.Type; + if (!columnType.IsValueType + || !BufferedDataReader.IsSupportedValueType(columnType)) + { + columnType = typeof(object); + valueExpression = Expression.Convert(valueExpression, typeof(object)); + } + + if (ProjectionColumns[index] == null) + { + ProjectionColumns[index] = ReaderColumn.Create( + columnType, + nullable, + _indexMapParameter != null ? ((ColumnExpression)_selectExpression.Projection[index].Expression).Name : null, + Expression.Lambda( + valueExpression, + dbDataReader, + _indexMapParameter ?? Expression.Parameter(typeof(int[]))).Compile()); + } + + if (getMethod.DeclaringType != typeof(DbDataReader)) + { + valueExpression + = Expression.Call( + dbDataReader, + RelationalTypeMapping.GetDataReaderMethod(columnType), + indexExpression); + } + } + valueExpression = typeMapping.CustomizeDataReaderExpression(valueExpression); var converter = typeMapping.Converter; diff --git a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs index 6eb38022f00..0ff1e0f4339 100644 --- a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs @@ -10,6 +10,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; +using Microsoft.EntityFrameworkCore.Storage; namespace Microsoft.EntityFrameworkCore.Query { @@ -54,16 +55,20 @@ protected override Expression VisitShapedQueryExpression(ShapedQueryExpression s shaper = InjectEntityMaterializers(shaper); - shaper = new RelationalProjectionBindingRemovingExpressionVisitor(selectExpression, dataReaderParameter) - .Visit(shaper); - shaper = new CustomShaperCompilingExpressionVisitor( - dataReaderParameter, resultCoordinatorParameter, IsTracking) + var isNonComposedFromSql = selectExpression.IsNonComposedFromSql(); + shaper = new RelationalProjectionBindingRemovingExpressionVisitor( + selectExpression, + dataReaderParameter, + isNonComposedFromSql ? indexMapParameter : null, + IsBuffering) + .Visit(shaper, out var projectionColumns); + + shaper = new CustomShaperCompilingExpressionVisitor(dataReaderParameter, resultCoordinatorParameter, IsTracking) .Visit(shaper); IReadOnlyList columnNames = null; - if (selectExpression.IsNonComposedFromSql()) + if (isNonComposedFromSql) { - shaper = new IndexMapInjectingExpressionVisitor(indexMapParameter).Visit(shaper); columnNames = selectExpression.Projection.Select(pe => ((ColumnExpression)pe.Expression).Name).ToList(); } @@ -82,33 +87,10 @@ protected override Expression VisitShapedQueryExpression(ShapedQueryExpression s Expression.Convert(QueryCompilationContext.QueryContextParameter, typeof(RelationalQueryContext)), Expression.Constant(relationalCommandCache), Expression.Constant(columnNames, typeof(IReadOnlyList)), + Expression.Constant(projectionColumns, typeof(IReadOnlyList)), Expression.Constant(shaperLambda.Compile()), Expression.Constant(_contextType), Expression.Constant(_logger)); } - - private class IndexMapInjectingExpressionVisitor : ExpressionVisitor - { - private readonly ParameterExpression _indexMapParameter; - - public IndexMapInjectingExpressionVisitor(ParameterExpression indexMapParameter) - { - _indexMapParameter = indexMapParameter; - } - - protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) - { - if (methodCallExpression.Object != null - && typeof(DbDataReader).IsAssignableFrom(methodCallExpression.Object.Type)) - { - var indexArgument = methodCallExpression.Arguments[0]; - return methodCallExpression.Update( - methodCallExpression.Object, - new[] { Expression.ArrayIndex(_indexMapParameter, indexArgument) }); - } - - return base.VisitMethodCall(methodCallExpression); - } - } } } diff --git a/src/EFCore.Relational/Storage/ReaderColumn.cs b/src/EFCore.Relational/Storage/ReaderColumn.cs new file mode 100644 index 00000000000..15136a143cb --- /dev/null +++ b/src/EFCore.Relational/Storage/ReaderColumn.cs @@ -0,0 +1,52 @@ +// 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.Concurrent; +using System.Reflection; +using JetBrains.Annotations; + +namespace Microsoft.EntityFrameworkCore.Storage +{ + /// + /// + /// An expected column in the relational data reader. + /// + /// + /// This type is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// + /// + public abstract class ReaderColumn + { + private static readonly ConcurrentDictionary _constructors + = new ConcurrentDictionary(); + + protected ReaderColumn([NotNull] Type type, bool nullable, [CanBeNull] string name) + { + Type = type; + IsNullable = nullable; + Name = name; + } + + public virtual Type Type { get; } + public virtual bool IsNullable { get; } + public virtual string Name { get; } + + /// + /// Creates an instance of . + /// + /// The type of the column. + /// Whether the column can contain null values. + /// The column name if it is used to access the column values, null otherwise. + /// + /// A used to get the field value for this column. + /// + /// An instance of . + public static ReaderColumn Create([NotNull] Type type, bool nullable, [CanBeNull] string columnName, [NotNull] object readFunc) + => (ReaderColumn)GetConstructor(type).Invoke(new[] { nullable, columnName, readFunc }); + + private static ConstructorInfo GetConstructor(Type type) + => _constructors.GetOrAdd(type, t => typeof(ReaderColumn<>).MakeGenericType(t).GetConstructors()[0]); + } +} diff --git a/src/EFCore.Relational/Storage/ReaderColumn`.cs b/src/EFCore.Relational/Storage/ReaderColumn`.cs new file mode 100644 index 00000000000..bbb0e47f5f0 --- /dev/null +++ b/src/EFCore.Relational/Storage/ReaderColumn`.cs @@ -0,0 +1,29 @@ +// 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.Data.Common; +using JetBrains.Annotations; + +namespace Microsoft.EntityFrameworkCore.Storage +{ + /// + /// + /// An expected column in the relational data reader. + /// + /// + /// This type is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// + /// + public class ReaderColumn : ReaderColumn + { + public ReaderColumn(bool nullable, [CanBeNull] string name, [NotNull] Func getFieldValue) + : base(typeof(T), nullable, name) + { + GetFieldValue = getFieldValue; + } + + public virtual Func GetFieldValue { get; } + } +} diff --git a/src/EFCore.Relational/Storage/RelationalCommand.cs b/src/EFCore.Relational/Storage/RelationalCommand.cs index ca9c6572d3e..9a653c17004 100644 --- a/src/EFCore.Relational/Storage/RelationalCommand.cs +++ b/src/EFCore.Relational/Storage/RelationalCommand.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Storage @@ -375,7 +376,10 @@ await logger.CommandErrorAsync( /// The result of the command. public virtual RelationalDataReader ExecuteReader(RelationalCommandParameterObject parameterObject) { - var (connection, context, logger) = (parameterObject.Connection, parameterObject.Context, parameterObject.Logger); + var connection = parameterObject.Connection; + var context = parameterObject.Context; + var readerColumns = parameterObject.ReaderColumns; + var logger = parameterObject.Logger; var commandId = Guid.NewGuid(); var command = CreateCommand(parameterObject, commandId, DbCommandMethod.ExecuteReader); @@ -414,6 +418,11 @@ public virtual RelationalDataReader ExecuteReader(RelationalCommandParameterObje stopwatch.Elapsed); } + if (readerColumns != null) + { + reader = new BufferedDataReader(reader).Initialize(readerColumns); + } + var result = new RelationalDataReader( connection, command, @@ -461,7 +470,10 @@ public virtual async Task ExecuteReaderAsync( RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken = default) { - var (connection, context, logger) = (parameterObject.Connection, parameterObject.Context, parameterObject.Logger); + var connection = parameterObject.Connection; + var context = parameterObject.Context; + var readerColumns = parameterObject.ReaderColumns; + var logger = parameterObject.Logger; var commandId = Guid.NewGuid(); var command = CreateCommand(parameterObject, commandId, DbCommandMethod.ExecuteReader); @@ -503,6 +515,11 @@ public virtual async Task ExecuteReaderAsync( cancellationToken); } + if (readerColumns != null) + { + reader = await new BufferedDataReader(reader).InitializeAsync(readerColumns, cancellationToken); + } + var result = new RelationalDataReader( connection, command, diff --git a/src/EFCore.Relational/Storage/RelationalCommandParameterObject.cs b/src/EFCore.Relational/Storage/RelationalCommandParameterObject.cs index 26ebcb9656a..6aea922e97c 100644 --- a/src/EFCore.Relational/Storage/RelationalCommandParameterObject.cs +++ b/src/EFCore.Relational/Storage/RelationalCommandParameterObject.cs @@ -30,11 +30,13 @@ public readonly struct RelationalCommandParameterObject /// /// The connection on which the command will execute. /// The SQL parameter values to use, or null if none. + /// The expected columns if the reader needs to be buffered, or null otherwise. /// The current instance, or null if it is not known. /// A logger, or null if no logger is available. public RelationalCommandParameterObject( [NotNull] IRelationalConnection connection, [CanBeNull] IReadOnlyDictionary parameterValues, + [CanBeNull] IReadOnlyList readerColumns, [CanBeNull] DbContext context, [CanBeNull] IDiagnosticsLogger logger) { @@ -42,6 +44,7 @@ public RelationalCommandParameterObject( Connection = connection; ParameterValues = parameterValues; + ReaderColumns = readerColumns; Context = context; Logger = logger; } @@ -56,6 +59,11 @@ public RelationalCommandParameterObject( /// public IReadOnlyDictionary ParameterValues { get; } + /// + /// The expected columns if the reader needs to be buffered, or null otherwise. + /// + public IReadOnlyList ReaderColumns { get; } + /// /// The current instance, or null if it is not known. /// diff --git a/src/EFCore.Relational/Storage/RelationalTypeMapping.cs b/src/EFCore.Relational/Storage/RelationalTypeMapping.cs index 4bdaf5933c9..61038d56262 100644 --- a/src/EFCore.Relational/Storage/RelationalTypeMapping.cs +++ b/src/EFCore.Relational/Storage/RelationalTypeMapping.cs @@ -523,10 +523,18 @@ public virtual MethodInfo GetDataReaderMethod() { var type = (Converter?.ProviderClrType ?? ClrType).UnwrapNullableType(); - return _getXMethods.TryGetValue(type, out var method) + return GetDataReaderMethod(type); + } + + /// + /// The method to use when reading values of the given type. The method must be defined + /// on . + /// + /// The method to use to read the value. + public static MethodInfo GetDataReaderMethod([NotNull] Type type) + => _getXMethods.TryGetValue(type, out var method) ? method : _getFieldValueMethod.MakeGenericMethod(type); - } /// /// Gets a custom expression tree for reading the value from the input data reader diff --git a/src/EFCore.Relational/Update/Internal/BatchExecutor.cs b/src/EFCore.Relational/Update/Internal/BatchExecutor.cs index 18c8a293574..3e35e31e650 100644 --- a/src/EFCore.Relational/Update/Internal/BatchExecutor.cs +++ b/src/EFCore.Relational/Update/Internal/BatchExecutor.cs @@ -1,6 +1,7 @@ // 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.Threading; using System.Threading.Tasks; @@ -37,7 +38,9 @@ public class BatchExecutor : IBatchExecutor public BatchExecutor([NotNull] ICurrentDbContext currentContext, [NotNull] IExecutionStrategyFactory executionStrategyFactory) { CurrentContext = currentContext; +#pragma warning disable 618 ExecutionStrategyFactory = executionStrategyFactory; +#pragma warning restore 618 } /// @@ -54,6 +57,7 @@ public BatchExecutor([NotNull] ICurrentDbContext currentContext, [NotNull] IExec /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [Obsolete("This isn't used anymore")] protected virtual IExecutionStrategyFactory ExecutionStrategyFactory { get; } /// @@ -65,14 +69,7 @@ public BatchExecutor([NotNull] ICurrentDbContext currentContext, [NotNull] IExec public virtual int Execute( IEnumerable commandBatches, IRelationalConnection connection) - => CurrentContext.Context.Database.AutoTransactionsEnabled - ? ExecutionStrategyFactory.Create().Execute((commandBatches, connection), Execute, null) - : Execute(CurrentContext.Context, (commandBatches, connection)); - - private int Execute(DbContext _, (IEnumerable, IRelationalConnection) parameters) { - var commandBatches = parameters.Item1; - var connection = parameters.Item2; var rowsAffected = 0; IDbContextTransaction startedTransaction = null; try @@ -118,21 +115,11 @@ private int Execute(DbContext _, (IEnumerable, IRelati /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public virtual Task ExecuteAsync( + public virtual async Task ExecuteAsync( IEnumerable commandBatches, IRelationalConnection connection, CancellationToken cancellationToken = default) - => CurrentContext.Context.Database.AutoTransactionsEnabled - ? ExecutionStrategyFactory.Create().ExecuteAsync((commandBatches, connection), ExecuteAsync, null, cancellationToken) - : ExecuteAsync(CurrentContext.Context, (commandBatches, connection), cancellationToken); - - private async Task ExecuteAsync( - DbContext _, - (IEnumerable, IRelationalConnection) parameters, - CancellationToken cancellationToken = default) { - var commandBatches = parameters.Item1; - var connection = parameters.Item2; var rowsAffected = 0; IDbContextTransaction startedTransaction = null; try diff --git a/src/EFCore.Relational/Update/ReaderModificationCommandBatch.cs b/src/EFCore.Relational/Update/ReaderModificationCommandBatch.cs index 75d8f1d01d8..59dd5ed4d0c 100644 --- a/src/EFCore.Relational/Update/ReaderModificationCommandBatch.cs +++ b/src/EFCore.Relational/Update/ReaderModificationCommandBatch.cs @@ -239,6 +239,7 @@ public override void Execute(IRelationalConnection connection) new RelationalCommandParameterObject( connection, storeCommand.ParameterValues, + null, Dependencies.CurrentContext.Context, Dependencies.Logger))) { @@ -276,6 +277,7 @@ public override async Task ExecuteAsync( new RelationalCommandParameterObject( connection, storeCommand.ParameterValues, + null, Dependencies.CurrentContext.Context, Dependencies.Logger), cancellationToken)) diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerCompiledQueryCacheKeyGenerator.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerCompiledQueryCacheKeyGenerator.cs index e0b6324b7cc..3a5be3c0086 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerCompiledQueryCacheKeyGenerator.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerCompiledQueryCacheKeyGenerator.cs @@ -64,8 +64,8 @@ public SqlServerCompiledQueryCacheKey( public override bool Equals(object obj) => !(obj is null) - && obj is SqlServerCompiledQueryCacheKey - && Equals((SqlServerCompiledQueryCacheKey)obj); + && obj is SqlServerCompiledQueryCacheKey key + && Equals(key); private bool Equals(SqlServerCompiledQueryCacheKey other) => _relationalCompiledQueryCacheKey.Equals(other._relationalCompiledQueryCacheKey) diff --git a/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs b/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs index f952b4f131d..81d20e5bfd7 100644 --- a/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs +++ b/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs @@ -121,6 +121,7 @@ public override bool HasTables() new RelationalCommandParameterObject( connection, null, + null, Dependencies.CurrentContext.Context, Dependencies.CommandLogger)) != 0); @@ -139,6 +140,7 @@ public override Task HasTablesAsync(CancellationToken cancellationToken = new RelationalCommandParameterObject( connection, null, + null, Dependencies.CurrentContext.Context, Dependencies.CommandLogger), cancellationToken: ct) @@ -198,6 +200,7 @@ private bool Exists(bool retryOnNotExists) new RelationalCommandParameterObject( _connection, null, + null, Dependencies.CurrentContext.Context, Dependencies.CommandLogger)); @@ -258,6 +261,7 @@ await _rawSqlCommandBuilder new RelationalCommandParameterObject( _connection, null, + null, Dependencies.CurrentContext.Context, Dependencies.CommandLogger), ct); diff --git a/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerSequenceHiLoValueGenerator.cs b/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerSequenceHiLoValueGenerator.cs index 4e7030c4626..fe284511fe4 100644 --- a/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerSequenceHiLoValueGenerator.cs +++ b/src/EFCore.SqlServer/ValueGeneration/Internal/SqlServerSequenceHiLoValueGenerator.cs @@ -63,8 +63,9 @@ protected override long GetNewLowValue() .ExecuteScalar( new RelationalCommandParameterObject( _connection, - null, - null, + parameterValues: null, + readerColumns: null, + context: null, _commandLogger)), typeof(long), CultureInfo.InvariantCulture); @@ -82,8 +83,9 @@ await _rawSqlCommandBuilder .ExecuteScalarAsync( new RelationalCommandParameterObject( _connection, - null, - null, + parameterValues: null, + readerColumns: null, + context: null, _commandLogger), cancellationToken), typeof(long), diff --git a/src/EFCore.Sqlite.Core/Storage/Internal/SqliteDatabaseCreator.cs b/src/EFCore.Sqlite.Core/Storage/Internal/SqliteDatabaseCreator.cs index 0513775c33c..03076df737c 100644 --- a/src/EFCore.Sqlite.Core/Storage/Internal/SqliteDatabaseCreator.cs +++ b/src/EFCore.Sqlite.Core/Storage/Internal/SqliteDatabaseCreator.cs @@ -64,6 +64,7 @@ public override void Create() Dependencies.Connection, null, null, + null, Dependencies.CommandLogger)); Dependencies.Connection.Close(); @@ -114,6 +115,7 @@ public override bool HasTables() Dependencies.Connection, null, null, + null, Dependencies.CommandLogger)); return count != 0; diff --git a/src/EFCore/ChangeTracking/Internal/StateManager.cs b/src/EFCore/ChangeTracking/Internal/StateManager.cs index 26dbdba0bd2..f8531d68bf2 100644 --- a/src/EFCore/ChangeTracking/Internal/StateManager.cs +++ b/src/EFCore/ChangeTracking/Internal/StateManager.cs @@ -884,47 +884,6 @@ public virtual IEntityFinder CreateEntityFinder(IEntityType entityType) /// public virtual int ChangedCount { get; set; } - /// - /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to - /// the same compatibility standards as public APIs. It may be changed or removed without notice in - /// any release. You should only use it directly in your code with extreme caution and knowing that - /// doing so can result in application failures when updating to a new Entity Framework Core release. - /// - public virtual int SaveChanges(bool acceptAllChangesOnSuccess) - { - if (ChangedCount == 0) - { - return 0; - } - - var entriesToSave = GetEntriesToSave(cascadeChanges: true); - if (entriesToSave.Count == 0) - { - return 0; - } - - try - { - var result = SaveChanges(entriesToSave); - - if (acceptAllChangesOnSuccess) - { - AcceptAllChanges((IReadOnlyList)entriesToSave); - } - - return result; - } - catch - { - foreach (var entry in entriesToSave) - { - ((InternalEntityEntry)entry).DiscardStoreGeneratedValues(); - } - - throw; - } - } - /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -1071,14 +1030,51 @@ private static bool KeyValuesEqual(IProperty property, object value, object curr ?.Equals(currentValue, value) ?? Equals(currentValue, value); + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public virtual async Task SaveChangesAsync( - bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default) + protected virtual int SaveChanges( + [NotNull] IList entriesToSave) + { + using (_concurrencyDetector.EnterCriticalSection()) + { + return _database.SaveChanges(entriesToSave); + } + } + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + protected virtual async Task SaveChangesAsync( + [NotNull] IList entriesToSave, + CancellationToken cancellationToken = default) + { + using (_concurrencyDetector.EnterCriticalSection()) + { + return await _database.SaveChangesAsync(entriesToSave, cancellationToken); + } + } + + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual int SaveChanges(bool acceptAllChangesOnSuccess) + => Context.Database.AutoTransactionsEnabled + ? Dependencies.ExecutionStrategyFactory.Create().Execute(acceptAllChangesOnSuccess, SaveChanges, null) + : SaveChanges(Context, acceptAllChangesOnSuccess); + + private int SaveChanges(DbContext _, bool acceptAllChangesOnSuccess) { if (ChangedCount == 0) { @@ -1093,7 +1089,7 @@ public virtual async Task SaveChangesAsync( try { - var result = await SaveChangesAsync(entriesToSave, cancellationToken); + var result = SaveChanges(entriesToSave); if (acceptAllChangesOnSuccess) { @@ -1119,28 +1115,45 @@ public virtual async Task SaveChangesAsync( /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - protected virtual int SaveChanges( - [NotNull] IList entriesToSave) + public virtual Task SaveChangesAsync( + bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default) + => Context.Database.AutoTransactionsEnabled + ? Dependencies.ExecutionStrategyFactory.Create().ExecuteAsync(acceptAllChangesOnSuccess, SaveChangesAsync, null, cancellationToken) + : SaveChangesAsync(Context, acceptAllChangesOnSuccess, cancellationToken); + + private async Task SaveChangesAsync( + DbContext _, bool acceptAllChangesOnSuccess, CancellationToken cancellationToken) { - using (_concurrencyDetector.EnterCriticalSection()) + if (ChangedCount == 0) { - return _database.SaveChanges(entriesToSave); + return 0; } - } - /// - /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to - /// the same compatibility standards as public APIs. It may be changed or removed without notice in - /// any release. You should only use it directly in your code with extreme caution and knowing that - /// doing so can result in application failures when updating to a new Entity Framework Core release. - /// - protected virtual async Task SaveChangesAsync( - [NotNull] IList entriesToSave, - CancellationToken cancellationToken = default) - { - using (_concurrencyDetector.EnterCriticalSection()) + var entriesToSave = GetEntriesToSave(cascadeChanges: true); + if (entriesToSave.Count == 0) { - return await _database.SaveChangesAsync(entriesToSave, cancellationToken); + return 0; + } + + try + { + var result = await SaveChangesAsync(entriesToSave, cancellationToken); + + if (acceptAllChangesOnSuccess) + { + AcceptAllChanges((IReadOnlyList)entriesToSave); + } + + return result; + } + catch + { + foreach (var entry in entriesToSave) + { + ((InternalEntityEntry)entry).DiscardStoreGeneratedValues(); + } + + throw; } } diff --git a/src/EFCore/ChangeTracking/Internal/StateManagerDependencies.cs b/src/EFCore/ChangeTracking/Internal/StateManagerDependencies.cs index 570f25c2862..55d89aafab8 100644 --- a/src/EFCore/ChangeTracking/Internal/StateManagerDependencies.cs +++ b/src/EFCore/ChangeTracking/Internal/StateManagerDependencies.cs @@ -75,6 +75,7 @@ public StateManagerDependencies( [NotNull] IEntityFinderSource entityFinderSource, [NotNull] IDbSetSource setSource, [NotNull] IEntityMaterializerSource entityMaterializerSource, + [NotNull] IExecutionStrategyFactory executionStrategyFactory, [NotNull] ILoggingOptions loggingOptions, [NotNull] IDiagnosticsLogger updateLogger, [NotNull] IDiagnosticsLogger changeTrackingLogger) @@ -90,6 +91,7 @@ public StateManagerDependencies( EntityFinderSource = entityFinderSource; SetSource = setSource; EntityMaterializerSource = entityMaterializerSource; + ExecutionStrategyFactory = executionStrategyFactory; LoggingOptions = loggingOptions; UpdateLogger = updateLogger; ChangeTrackingLogger = changeTrackingLogger; @@ -183,6 +185,14 @@ public StateManagerDependencies( /// public IEntityMaterializerSource EntityMaterializerSource { get; } + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public IExecutionStrategyFactory ExecutionStrategyFactory { get; } + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -225,6 +235,7 @@ public StateManagerDependencies With([NotNull] IInternalEntityEntryFactory inter EntityFinderSource, SetSource, EntityMaterializerSource, + ExecutionStrategyFactory, LoggingOptions, UpdateLogger, ChangeTrackingLogger); @@ -247,6 +258,7 @@ public StateManagerDependencies With([NotNull] IInternalEntityEntrySubscriber in EntityFinderSource, SetSource, EntityMaterializerSource, + ExecutionStrategyFactory, LoggingOptions, UpdateLogger, ChangeTrackingLogger); @@ -269,6 +281,7 @@ public StateManagerDependencies With([NotNull] IInternalEntityEntryNotifier inte EntityFinderSource, SetSource, EntityMaterializerSource, + ExecutionStrategyFactory, LoggingOptions, UpdateLogger, ChangeTrackingLogger); @@ -291,6 +304,7 @@ public StateManagerDependencies With([NotNull] ValueGenerationManager valueGener EntityFinderSource, SetSource, EntityMaterializerSource, + ExecutionStrategyFactory, LoggingOptions, UpdateLogger, ChangeTrackingLogger); @@ -313,6 +327,7 @@ public StateManagerDependencies With([NotNull] IModel model) EntityFinderSource, SetSource, EntityMaterializerSource, + ExecutionStrategyFactory, LoggingOptions, UpdateLogger, ChangeTrackingLogger); @@ -335,6 +350,7 @@ public StateManagerDependencies With([NotNull] IDatabase database) EntityFinderSource, SetSource, EntityMaterializerSource, + ExecutionStrategyFactory, LoggingOptions, UpdateLogger, ChangeTrackingLogger); @@ -357,6 +373,7 @@ public StateManagerDependencies With([NotNull] IConcurrencyDetector concurrencyD EntityFinderSource, SetSource, EntityMaterializerSource, + ExecutionStrategyFactory, LoggingOptions, UpdateLogger, ChangeTrackingLogger); @@ -379,6 +396,7 @@ public StateManagerDependencies With([NotNull] ICurrentDbContext currentContext) EntityFinderSource, SetSource, EntityMaterializerSource, + ExecutionStrategyFactory, LoggingOptions, UpdateLogger, ChangeTrackingLogger); @@ -401,6 +419,7 @@ public StateManagerDependencies With([NotNull] IEntityFinderSource entityFinderS entityFinderSource, SetSource, EntityMaterializerSource, + ExecutionStrategyFactory, LoggingOptions, UpdateLogger, ChangeTrackingLogger); @@ -423,6 +442,7 @@ public StateManagerDependencies With([NotNull] IDbSetSource setSource) EntityFinderSource, setSource, EntityMaterializerSource, + ExecutionStrategyFactory, LoggingOptions, UpdateLogger, ChangeTrackingLogger); @@ -445,6 +465,31 @@ public StateManagerDependencies With([NotNull] IEntityMaterializerSource entityM EntityFinderSource, SetSource, entityMaterializerSource, + ExecutionStrategyFactory, + LoggingOptions, + UpdateLogger, + ChangeTrackingLogger); + + + /// + /// Clones this dependency parameter object with one service replaced. + /// + /// A replacement for the current dependency of this type. + /// A new parameter object with the given service replaced. + public StateManagerDependencies With([NotNull] IExecutionStrategyFactory executionStrategyFactory) + => new StateManagerDependencies( + InternalEntityEntryFactory, + InternalEntityEntrySubscriber, + InternalEntityEntryNotifier, + ValueGenerationManager, + Model, + Database, + ConcurrencyDetector, + CurrentContext, + EntityFinderSource, + SetSource, + EntityMaterializerSource, + executionStrategyFactory, LoggingOptions, UpdateLogger, ChangeTrackingLogger); @@ -467,6 +512,7 @@ public StateManagerDependencies With([NotNull] ILoggingOptions loggingOptions) EntityFinderSource, SetSource, EntityMaterializerSource, + ExecutionStrategyFactory, loggingOptions, UpdateLogger, ChangeTrackingLogger); @@ -489,6 +535,7 @@ public StateManagerDependencies With([NotNull] IDiagnosticsLogger public sealed class CompiledQueryCacheKeyGeneratorDependencies { + private readonly IExecutionStrategyFactory _executionStrategyFactory; + /// /// /// Creates the service dependencies parameter object for a . @@ -51,20 +54,26 @@ public sealed class CompiledQueryCacheKeyGeneratorDependencies /// the constructor at any point in this process. /// /// - /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to - /// the same compatibility standards as public APIs. It may be changed or removed without notice in - /// any release. You should only use it directly in your code with extreme caution and knowing that - /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// The service lifetime is . This means that each + /// instance will use its own instance of this service. + /// The implementation may depend on other services registered with any lifetime. + /// The implementation does not need to be thread-safe. /// /// [EntityFrameworkInternal] - public CompiledQueryCacheKeyGeneratorDependencies([NotNull] IModel model, [NotNull] ICurrentDbContext currentContext) + public CompiledQueryCacheKeyGeneratorDependencies( + [NotNull] IModel model, + [NotNull] ICurrentDbContext currentContext, + [NotNull] IExecutionStrategyFactory executionStrategyFactory) { Check.NotNull(model, nameof(model)); Check.NotNull(currentContext, nameof(currentContext)); + Check.NotNull(executionStrategyFactory, nameof(executionStrategyFactory)); Model = model; CurrentContext = currentContext; + _executionStrategyFactory = executionStrategyFactory; + IsRetryingExecutionStrategy = executionStrategyFactory.Create().RetriesOnFailure; } /// @@ -77,13 +86,18 @@ public CompiledQueryCacheKeyGeneratorDependencies([NotNull] IModel model, [NotNu /// public ICurrentDbContext CurrentContext { get; } + /// + /// Whether the configured execution strategy can retry. + /// + public bool IsRetryingExecutionStrategy { get; } + /// /// Clones this dependency parameter object with one service replaced. /// /// A replacement for the current dependency of this type. /// A new parameter object with the given service replaced. public CompiledQueryCacheKeyGeneratorDependencies With([NotNull] IModel model) - => new CompiledQueryCacheKeyGeneratorDependencies(model, CurrentContext); + => new CompiledQueryCacheKeyGeneratorDependencies(model, CurrentContext, _executionStrategyFactory); /// /// Clones this dependency parameter object with one service replaced. @@ -91,6 +105,14 @@ public CompiledQueryCacheKeyGeneratorDependencies With([NotNull] IModel model) /// A replacement for the current dependency of this type. /// A new parameter object with the given service replaced. public CompiledQueryCacheKeyGeneratorDependencies With([NotNull] ICurrentDbContext currentContext) - => new CompiledQueryCacheKeyGeneratorDependencies(Model, currentContext); + => new CompiledQueryCacheKeyGeneratorDependencies(Model, currentContext, _executionStrategyFactory); + + /// + /// Clones this dependency parameter object with one service replaced. + /// + /// A replacement for the current dependency of this type. + /// A new parameter object with the given service replaced. + public CompiledQueryCacheKeyGeneratorDependencies With([NotNull] IExecutionStrategyFactory executionStrategyFactory) + => new CompiledQueryCacheKeyGeneratorDependencies(Model, CurrentContext, executionStrategyFactory); } } diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs index 1cfea0a06b8..5497686ecff 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs @@ -165,8 +165,8 @@ protected Expression ExpandNavigation( innerEntityReference.SetIncludePaths(innerIncludeTreeNode); } - var innerSoureSequenceType = innerSource.Type.GetSequenceType(); - var innerParameter = Expression.Parameter(innerSoureSequenceType, "i"); + var innerSourceSequenceType = innerSource.Type.GetSequenceType(); + var innerParameter = Expression.Parameter(innerSourceSequenceType, "i"); Expression outerKey; if (root is NavigationExpansionExpression innerNavigationExpansionExpression && innerNavigationExpansionExpression.CardinalityReducingGenericMethodInfo != null) @@ -228,7 +228,7 @@ protected Expression ExpandNavigation( : Expression.Equal(outerKey, innerKey); var subquery = Expression.Call( - QueryableMethods.Where.MakeGenericMethod(innerSoureSequenceType), + QueryableMethods.Where.MakeGenericMethod(innerSourceSequenceType), innerSource, Expression.Quote( Expression.Lambda( diff --git a/src/EFCore/Query/QueryCompilationContext.cs b/src/EFCore/Query/QueryCompilationContext.cs index 689c0c07004..71d60801dc0 100644 --- a/src/EFCore/Query/QueryCompilationContext.cs +++ b/src/EFCore/Query/QueryCompilationContext.cs @@ -36,6 +36,7 @@ public QueryCompilationContext( IsAsync = async; IsTracking = context.ChangeTracker.QueryTrackingBehavior == QueryTrackingBehavior.TrackAll; + IsBuffering = dependencies.IsRetryingExecutionStrategy; Model = dependencies.Model; ContextOptions = dependencies.ContextOptions; ContextType = context.GetType(); @@ -51,6 +52,7 @@ public QueryCompilationContext( public virtual IModel Model { get; } public virtual IDbContextOptions ContextOptions { get; } public virtual bool IsTracking { get; internal set; } + public virtual bool IsBuffering { get; } public virtual bool IgnoreQueryFilters { get; internal set; } public virtual ISet Tags { get; } = new HashSet(); public virtual IDiagnosticsLogger Logger { get; } diff --git a/src/EFCore/Query/QueryCompilationContextDependencies.cs b/src/EFCore/Query/QueryCompilationContextDependencies.cs index 943b21787a7..95101aa3623 100644 --- a/src/EFCore/Query/QueryCompilationContextDependencies.cs +++ b/src/EFCore/Query/QueryCompilationContextDependencies.cs @@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Utilities; using Microsoft.Extensions.DependencyInjection; @@ -35,6 +36,8 @@ namespace Microsoft.EntityFrameworkCore.Query /// public sealed class QueryCompilationContextDependencies { + private readonly IExecutionStrategyFactory _executionStrategyFactory; + /// /// /// Creates the service dependencies parameter object for a . @@ -61,6 +64,7 @@ public QueryCompilationContextDependencies( [NotNull] IQueryableMethodTranslatingExpressionVisitorFactory queryableMethodTranslatingExpressionVisitorFactory, [NotNull] IQueryTranslationPostprocessorFactory queryTranslationPostprocessorFactory, [NotNull] IShapedQueryCompilingExpressionVisitorFactory shapedQueryCompilingExpressionVisitorFactory, + [NotNull] IExecutionStrategyFactory executionStrategyFactory, [NotNull] ICurrentDbContext currentContext, [NotNull] IDbContextOptions contextOptions, [NotNull] IDiagnosticsLogger logger) @@ -70,6 +74,7 @@ public QueryCompilationContextDependencies( Check.NotNull(queryableMethodTranslatingExpressionVisitorFactory, nameof(queryableMethodTranslatingExpressionVisitorFactory)); Check.NotNull(queryTranslationPostprocessorFactory, nameof(queryTranslationPostprocessorFactory)); Check.NotNull(shapedQueryCompilingExpressionVisitorFactory, nameof(shapedQueryCompilingExpressionVisitorFactory)); + Check.NotNull(executionStrategyFactory, nameof(executionStrategyFactory)); Check.NotNull(currentContext, nameof(currentContext)); Check.NotNull(contextOptions, nameof(contextOptions)); Check.NotNull(logger, nameof(logger)); @@ -80,6 +85,8 @@ public QueryCompilationContextDependencies( QueryableMethodTranslatingExpressionVisitorFactory = queryableMethodTranslatingExpressionVisitorFactory; QueryTranslationPostprocessorFactory = queryTranslationPostprocessorFactory; ShapedQueryCompilingExpressionVisitorFactory = shapedQueryCompilingExpressionVisitorFactory; + _executionStrategyFactory = executionStrategyFactory; + IsRetryingExecutionStrategy = executionStrategyFactory.Create().RetriesOnFailure; ContextOptions = contextOptions; Logger = logger; } @@ -114,6 +121,11 @@ public QueryCompilationContextDependencies( /// public IShapedQueryCompilingExpressionVisitorFactory ShapedQueryCompilingExpressionVisitorFactory { get; } + /// + /// Whether the configured execution strategy can retry. + /// + public bool IsRetryingExecutionStrategy { get; } + /// /// The context options. /// @@ -136,6 +148,7 @@ public QueryCompilationContextDependencies With([NotNull] IModel model) QueryableMethodTranslatingExpressionVisitorFactory, QueryTranslationPostprocessorFactory, ShapedQueryCompilingExpressionVisitorFactory, + _executionStrategyFactory, CurrentContext, ContextOptions, Logger); @@ -152,6 +165,7 @@ public QueryCompilationContextDependencies With([NotNull] IQueryTranslationPrepr QueryableMethodTranslatingExpressionVisitorFactory, QueryTranslationPostprocessorFactory, ShapedQueryCompilingExpressionVisitorFactory, + _executionStrategyFactory, CurrentContext, ContextOptions, Logger); @@ -169,6 +183,7 @@ public QueryCompilationContextDependencies With( queryableMethodTranslatingExpressionVisitorFactory, QueryTranslationPostprocessorFactory, ShapedQueryCompilingExpressionVisitorFactory, + _executionStrategyFactory, CurrentContext, ContextOptions, Logger); @@ -186,6 +201,7 @@ public QueryCompilationContextDependencies With( QueryableMethodTranslatingExpressionVisitorFactory, queryTranslationPostprocessorFactory, ShapedQueryCompilingExpressionVisitorFactory, + _executionStrategyFactory, CurrentContext, ContextOptions, Logger); @@ -203,6 +219,24 @@ public QueryCompilationContextDependencies With( QueryableMethodTranslatingExpressionVisitorFactory, QueryTranslationPostprocessorFactory, shapedQueryCompilingExpressionVisitorFactory, + _executionStrategyFactory, + CurrentContext, + ContextOptions, + Logger); + + /// + /// Clones this dependency parameter object with one service replaced. + /// + /// A replacement for the current dependency of this type. + /// A new parameter object with the given service replaced. + public QueryCompilationContextDependencies With([NotNull] IExecutionStrategyFactory executionStrategyFactory) + => new QueryCompilationContextDependencies( + Model, + QueryTranslationPreprocessorFactory, + QueryableMethodTranslatingExpressionVisitorFactory, + QueryTranslationPostprocessorFactory, + ShapedQueryCompilingExpressionVisitorFactory, + executionStrategyFactory, CurrentContext, ContextOptions, Logger); @@ -219,6 +253,7 @@ public QueryCompilationContextDependencies With([NotNull] ICurrentDbContext curr QueryableMethodTranslatingExpressionVisitorFactory, QueryTranslationPostprocessorFactory, ShapedQueryCompilingExpressionVisitorFactory, + _executionStrategyFactory, currentContext, ContextOptions, Logger); @@ -235,6 +270,7 @@ public QueryCompilationContextDependencies With([NotNull] IDbContextOptions cont QueryableMethodTranslatingExpressionVisitorFactory, QueryTranslationPostprocessorFactory, ShapedQueryCompilingExpressionVisitorFactory, + _executionStrategyFactory, CurrentContext, contextOptions, Logger); @@ -251,6 +287,7 @@ public QueryCompilationContextDependencies With([NotNull] IDiagnosticsLogger Dependencies.QueryProvider; + /// + /// The execution strategy factory. + /// + /// + /// The execution strategy factory. + /// + public virtual IExecutionStrategyFactory ExecutionStrategyFactory + => Dependencies.ExecutionStrategyFactory; + /// /// Gets the concurrency detector. /// diff --git a/src/EFCore/Query/QueryContextDependencies.cs b/src/EFCore/Query/QueryContextDependencies.cs index 8fb976b5ce7..b9c57db4867 100644 --- a/src/EFCore/Query/QueryContextDependencies.cs +++ b/src/EFCore/Query/QueryContextDependencies.cs @@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Internal; +using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Utilities; using Microsoft.Extensions.DependencyInjection; @@ -59,16 +60,19 @@ public sealed class QueryContextDependencies [EntityFrameworkInternal] public QueryContextDependencies( [NotNull] ICurrentDbContext currentContext, + [NotNull] IExecutionStrategyFactory executionStrategyFactory, [NotNull] IConcurrencyDetector concurrencyDetector, [NotNull] IDiagnosticsLogger commandLogger, [NotNull] IDiagnosticsLogger queryLogger) { Check.NotNull(currentContext, nameof(currentContext)); + Check.NotNull(executionStrategyFactory, nameof(executionStrategyFactory)); Check.NotNull(concurrencyDetector, nameof(concurrencyDetector)); Check.NotNull(commandLogger, nameof(commandLogger)); Check.NotNull(queryLogger, nameof(queryLogger)); CurrentContext = currentContext; + ExecutionStrategyFactory = executionStrategyFactory; ConcurrencyDetector = concurrencyDetector; CommandLogger = commandLogger; QueryLogger = queryLogger; @@ -93,6 +97,11 @@ public QueryContextDependencies( /// public IQueryProvider QueryProvider => CurrentContext.GetDependencies().QueryProvider; + /// + /// The execution strategy. + /// + public IExecutionStrategyFactory ExecutionStrategyFactory { get; } + /// /// Gets the concurrency detector. /// @@ -114,7 +123,14 @@ public QueryContextDependencies( /// A replacement for the current dependency of this type. /// A new parameter object with the given service replaced. public QueryContextDependencies With([NotNull] ICurrentDbContext currentContext) - => new QueryContextDependencies(currentContext, ConcurrencyDetector, CommandLogger, QueryLogger); + => new QueryContextDependencies(currentContext, ExecutionStrategyFactory, ConcurrencyDetector, CommandLogger, QueryLogger); + /// + /// Clones this dependency parameter object with one service replaced. + /// + /// A replacement for the current dependency of this type. + /// A new parameter object with the given service replaced. + public QueryContextDependencies With([NotNull] IExecutionStrategyFactory executionStrategyFactor) + => new QueryContextDependencies(CurrentContext, executionStrategyFactor, ConcurrencyDetector, CommandLogger, QueryLogger); /// /// Clones this dependency parameter object with one service replaced. @@ -122,7 +138,7 @@ public QueryContextDependencies With([NotNull] ICurrentDbContext currentContext) /// A replacement for the current dependency of this type. /// A new parameter object with the given service replaced. public QueryContextDependencies With([NotNull] IConcurrencyDetector concurrencyDetector) - => new QueryContextDependencies(CurrentContext, concurrencyDetector, CommandLogger, QueryLogger); + => new QueryContextDependencies(CurrentContext, ExecutionStrategyFactory, concurrencyDetector, CommandLogger, QueryLogger); /// /// Clones this dependency parameter object with one service replaced. @@ -130,7 +146,7 @@ public QueryContextDependencies With([NotNull] IConcurrencyDetector concurrencyD /// A replacement for the current dependency of this type. /// A new parameter object with the given service replaced. public QueryContextDependencies With([NotNull] IDiagnosticsLogger commandLogger) - => new QueryContextDependencies(CurrentContext, ConcurrencyDetector, commandLogger, QueryLogger); + => new QueryContextDependencies(CurrentContext, ExecutionStrategyFactory, ConcurrencyDetector, commandLogger, QueryLogger); /// /// Clones this dependency parameter object with one service replaced. @@ -138,6 +154,6 @@ public QueryContextDependencies With([NotNull] IDiagnosticsLogger A replacement for the current dependency of this type. /// A new parameter object with the given service replaced. public QueryContextDependencies With([NotNull] IDiagnosticsLogger queryLogger) - => new QueryContextDependencies(CurrentContext, ConcurrencyDetector, CommandLogger, queryLogger); + => new QueryContextDependencies(CurrentContext, ExecutionStrategyFactory, ConcurrencyDetector, CommandLogger, queryLogger); } } diff --git a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs index 97a4ff7b8d1..94c67f2a4cd 100644 --- a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs +++ b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs @@ -41,6 +41,7 @@ protected ShapedQueryCompilingExpressionVisitor( _constantVerifyingExpressionVisitor = new ConstantVerifyingExpressionVisitor(dependencies.TypeMappingSource); + IsBuffering = queryCompilationContext.IsBuffering; IsAsync = queryCompilationContext.IsAsync; if (queryCompilationContext.IsAsync) @@ -55,6 +56,8 @@ protected ShapedQueryCompilingExpressionVisitor( protected virtual bool IsTracking { get; } + public virtual bool IsBuffering { get; internal set; } + protected virtual bool IsAsync { get; } protected override Expression VisitExtension(Expression extensionExpression) diff --git a/src/EFCore/Storage/ExecutionStrategyExtensions.cs b/src/EFCore/Storage/ExecutionStrategyExtensions.cs index 9cbcd076c9e..c1c13774605 100644 --- a/src/EFCore/Storage/ExecutionStrategyExtensions.cs +++ b/src/EFCore/Storage/ExecutionStrategyExtensions.cs @@ -283,7 +283,7 @@ public static TResult Execute( [NotNull] this IExecutionStrategy strategy, [CanBeNull] TState state, [NotNull] Func operation) - => strategy.Execute(operation, verifySucceeded: null, state: state); + => strategy.Execute(state, operation, verifySucceeded: null); /// /// Executes the specified asynchronous operation and returns the result. @@ -330,14 +330,40 @@ public static Task ExecuteAsync( /// public static TResult Execute( [NotNull] this IExecutionStrategy strategy, + [CanBeNull] TState state, [NotNull] Func operation, - [CanBeNull] Func> verifySucceeded, - [CanBeNull] TState state) + [CanBeNull] Func> verifySucceeded) => Check.NotNull(strategy, nameof(strategy)).Execute( state, (c, s) => operation(s), verifySucceeded == null ? (Func>)null : (c, s) => verifySucceeded(s)); + /// + /// Executes the specified operation and returns the result. + /// + /// The strategy that will be used for the execution. + /// + /// A delegate representing an executable operation that returns the result of type . + /// + /// A delegate that tests whether the operation succeeded even though an exception was thrown. + /// The state that will be passed to the operation. + /// The type of the state. + /// The return type of . + /// The result from the operation. + /// + /// The operation has not succeeded after the configured number of retries. + /// + [Obsolete("Use overload that takes the state first")] + public static TResult Execute( + [NotNull] this IExecutionStrategy strategy, + [NotNull] Func operation, + [CanBeNull] Func> verifySucceeded, + [CanBeNull] TState state) + => strategy.Execute( + state, + operation, + verifySucceeded); + /// /// Executes the specified asynchronous operation and returns the result. /// diff --git a/test/EFCore.Cosmos.FunctionalTests/TestUtilities/TestSqlServerRetryingExecutionStrategy.cs b/test/EFCore.Cosmos.FunctionalTests/TestUtilities/TestCosmosExecutionStrategy.cs similarity index 96% rename from test/EFCore.Cosmos.FunctionalTests/TestUtilities/TestSqlServerRetryingExecutionStrategy.cs rename to test/EFCore.Cosmos.FunctionalTests/TestUtilities/TestCosmosExecutionStrategy.cs index f61dcd5be22..e56eea6d9c4 100644 --- a/test/EFCore.Cosmos.FunctionalTests/TestUtilities/TestSqlServerRetryingExecutionStrategy.cs +++ b/test/EFCore.Cosmos.FunctionalTests/TestUtilities/TestCosmosExecutionStrategy.cs @@ -6,6 +6,7 @@ using Microsoft.EntityFrameworkCore.Cosmos.TestUtilities; using Microsoft.EntityFrameworkCore.Storage; +// ReSharper disable once CheckNamespace namespace Microsoft.EntityFrameworkCore.TestUtilities { public class TestCosmosExecutionStrategy : CosmosExecutionStrategy diff --git a/test/EFCore.Relational.Specification.Tests/CommandInterceptionTestBase.cs b/test/EFCore.Relational.Specification.Tests/CommandInterceptionTestBase.cs index f0de0b127a3..419d9b95e8f 100644 --- a/test/EFCore.Relational.Specification.Tests/CommandInterceptionTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/CommandInterceptionTestBase.cs @@ -14,6 +14,7 @@ using Microsoft.EntityFrameworkCore.Storage; using Xunit; +// ReSharper disable InconsistentNaming namespace Microsoft.EntityFrameworkCore { public abstract class CommandInterceptionTestBase : InterceptionTestBase @@ -78,7 +79,7 @@ public virtual async Task Intercept_scalar_passively(bool async, bool inject) var connection = context.GetService(); var logger = context.GetService>(); - var commandParameterObject = new RelationalCommandParameterObject(connection, null, context, logger); + var commandParameterObject = new RelationalCommandParameterObject(connection, null, null, context, logger); using (var listener = Fixture.SubscribeToDiagnosticListener(context.ContextId)) { @@ -292,7 +293,7 @@ public virtual async Task Intercept_scalar_to_suppress_execution(bool async, boo var connection = context.GetService(); var logger = context.GetService>(); - var commandParameterObject = new RelationalCommandParameterObject(connection, null, context, logger); + var commandParameterObject = new RelationalCommandParameterObject(connection, null, null, context, logger); using (var listener = Fixture.SubscribeToDiagnosticListener(context.ContextId)) { @@ -483,7 +484,7 @@ public virtual async Task Intercept_scalar_to_mutate_command(bool async, bool in var connection = context.GetService(); var logger = context.GetService>(); - var commandParameterObject = new RelationalCommandParameterObject(connection, null, context, logger); + var commandParameterObject = new RelationalCommandParameterObject(connection, null, null, context, logger); using (var listener = Fixture.SubscribeToDiagnosticListener(context.ContextId)) { @@ -683,7 +684,7 @@ public virtual async Task Intercept_scalar_to_replace_execution(bool async, bool var connection = context.GetService(); var logger = context.GetService>(); - var commandParameterObject = new RelationalCommandParameterObject(connection, null, context, logger); + var commandParameterObject = new RelationalCommandParameterObject(connection, null, null, context, logger); using (var listener = Fixture.SubscribeToDiagnosticListener(context.ContextId)) { @@ -891,6 +892,20 @@ public CompositeFakeDbDataReader(DbDataReader firstReader, DbDataReader secondRe _secondReader = secondReader; } + public override int FieldCount => _firstReader.FieldCount; + public override int RecordsAffected => _firstReader.RecordsAffected + _secondReader.RecordsAffected; + public override bool HasRows => _firstReader.HasRows || _secondReader.HasRows; + public override bool IsClosed => _firstReader.IsClosed; + public override int Depth => _firstReader.Depth; + + public override string GetDataTypeName(int ordinal) => _firstReader.GetDataTypeName(ordinal); + public override Type GetFieldType(int ordinal) => _firstReader.GetFieldType(ordinal); + public override string GetName(int ordinal) => _firstReader.GetName(ordinal); + public override bool NextResult() => _firstReader.NextResult() || _secondReader.NextResult(); + + public override async Task NextResultAsync(CancellationToken cancellationToken) + => await _firstReader.NextResultAsync(cancellationToken) || await _secondReader.NextResultAsync(cancellationToken); + public override void Close() { _firstReader.Close(); @@ -948,7 +963,7 @@ public virtual async Task Intercept_scalar_to_replace_result(bool async, bool in var connection = context.GetService(); var logger = context.GetService>(); - var commandParameterObject = new RelationalCommandParameterObject(connection, null, context, logger); + var commandParameterObject = new RelationalCommandParameterObject(connection, null, null, context, logger); using (var listener = Fixture.SubscribeToDiagnosticListener(context.ContextId)) { @@ -1104,7 +1119,7 @@ public virtual async Task Intercept_scalar_that_throws(bool async, bool inject) var connection = context.GetService(); var logger = context.GetService>(); - var commandParameterObject = new RelationalCommandParameterObject(connection, null, context, logger); + var commandParameterObject = new RelationalCommandParameterObject(connection, null, null, context, logger); try { @@ -1188,7 +1203,7 @@ public virtual async Task Intercept_scalar_to_throw(bool async, bool inject) var connection = context.GetService(); var logger = context.GetService>(); - var commandParameterObject = new RelationalCommandParameterObject(connection, null, context, logger); + var commandParameterObject = new RelationalCommandParameterObject(connection, null, null, context, logger); var exception = async ? await Assert.ThrowsAsync(() => command.ExecuteScalarAsync(commandParameterObject)) @@ -1323,7 +1338,7 @@ private static async Task TestCompositeScalarInterceptors(UniverseContext contex var connection = context.GetService(); var logger = context.GetService>(); - var commandParameterObject = new RelationalCommandParameterObject(connection, null, context, logger); + var commandParameterObject = new RelationalCommandParameterObject(connection, null, null, context, logger); Assert.Equal( ResultReplacingScalarCommandInterceptor.InterceptedResult, @@ -1520,6 +1535,11 @@ private class FakeDbDataReader : DbDataReader private readonly int[] _ints = { 977, 988, 999 }; private readonly string[] _strings = { "<977>", "<988>", "<999>" }; + public override int FieldCount { get; } + public override int RecordsAffected { get; } + public override bool HasRows { get; } + public override bool IsClosed { get; } + public override int Depth { get; } public override bool Read() => _index++ < _ints.Length; @@ -1557,14 +1577,9 @@ public override long GetChars(int ordinal, long dataOffset, char[] buffer, int b public override int GetOrdinal(string name) => throw new NotImplementedException(); public override object GetValue(int ordinal) => throw new NotImplementedException(); public override int GetValues(object[] values) => throw new NotImplementedException(); - public override int FieldCount { get; } public override object this[int ordinal] => throw new NotImplementedException(); public override object this[string name] => throw new NotImplementedException(); - public override int RecordsAffected { get; } - public override bool HasRows { get; } - public override bool IsClosed { get; } public override bool NextResult() => throw new NotImplementedException(); - public override int Depth { get; } public override IEnumerator GetEnumerator() => throw new NotImplementedException(); } diff --git a/test/EFCore.Relational.Specification.Tests/Query/AsyncFromSqlQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/AsyncFromSqlQueryTestBase.cs index e523e716dba..b26d4f52601 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/AsyncFromSqlQueryTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/AsyncFromSqlQueryTestBase.cs @@ -30,7 +30,7 @@ public virtual async Task FromSqlRaw_queryable_simple() using (var context = CreateContext()) { var actual = await context.Set() - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [ContactName] LIKE '%z%'")) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [ContactName] LIKE '%z%'")) .ToArrayAsync(); Assert.Equal(14, actual.Length); @@ -44,7 +44,7 @@ public virtual async Task FromSqlRaw_queryable_simple_columns_out_of_order() using (var context = CreateContext()) { var actual = await context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( "SELECT [Region], [PostalCode], [Phone], [Fax], [CustomerID], [Country], [ContactTitle], [ContactName], [CompanyName], [City], [Address] FROM [Customers]")) .ToArrayAsync(); @@ -59,7 +59,7 @@ public virtual async Task FromSqlRaw_queryable_simple_columns_out_of_order_and_e using (var context = CreateContext()) { var actual = await context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( "SELECT [Region], [PostalCode], [PostalCode] AS [Foo], [Phone], [Fax], [CustomerID], [Country], [ContactTitle], [ContactName], [CompanyName], [City], [Address] FROM [Customers]")) .ToArrayAsync(); @@ -73,7 +73,7 @@ public virtual async Task FromSqlRaw_queryable_composed() { using (var context = CreateContext()) { - var actual = await context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) + var actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) .Where(c => c.ContactName.Contains("z")) .ToArrayAsync(); @@ -87,8 +87,8 @@ public virtual async Task FromSqlRaw_queryable_multiple_composed() using (var context = CreateContext()) { var actual - = await (from c in context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) - from o in context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Orders]")) + = await (from c in context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) + from o in context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Orders]")) where c.CustomerID == o.CustomerID select new { c, o }) .ToArrayAsync(); @@ -106,9 +106,9 @@ public virtual async Task FromSqlRaw_queryable_multiple_composed_with_closure_pa using (var context = CreateContext()) { var actual - = await (from c in context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) + = await (from c in context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) from o in context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), startDate, + NormalizeDelimitersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), startDate, endDate) where c.CustomerID == o.CustomerID select new { c, o }) @@ -129,9 +129,9 @@ public virtual async Task FromSqlRaw_queryable_multiple_composed_with_parameters { var actual = await (from c in context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) from o in context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), startDate, + NormalizeDelimitersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), startDate, endDate) where c.CustomerID == o.CustomerID select new { c, o }) @@ -147,7 +147,7 @@ public virtual async Task FromSqlRaw_queryable_multiple_line_query() using (var context = CreateContext()) { var actual = await context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( @"SELECT * FROM [Customers] WHERE [City] = 'London'")) @@ -164,7 +164,7 @@ public virtual async Task FromSqlRaw_queryable_composed_multiple_line_query() using (var context = CreateContext()) { var actual = await context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( @"SELECT * FROM [Customers]")) .Where(c => c.City == "London") @@ -184,7 +184,7 @@ public virtual async Task FromSqlRaw_queryable_with_parameters() using (var context = CreateContext()) { var actual = await context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"), city, + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"), city, contactTitle) .ToArrayAsync(); @@ -203,7 +203,7 @@ public virtual async Task FromSqlRaw_queryable_with_parameters_and_closure() using (var context = CreateContext()) { var actual = await context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) .Where(c => c.ContactTitle == contactTitle) .ToArrayAsync(); @@ -219,14 +219,14 @@ public virtual async Task FromSqlRaw_queryable_simple_cache_key_includes_query_s using (var context = CreateContext()) { var actual = await context.Set() - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = 'London'")) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'London'")) .ToArrayAsync(); Assert.Equal(6, actual.Length); Assert.True(actual.All(c => c.City == "London")); actual = await context.Set() - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = 'Seattle'")) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'Seattle'")) .ToArrayAsync(); Assert.Single(actual); @@ -243,7 +243,7 @@ public virtual async Task FromSqlRaw_queryable_with_parameters_cache_key_include using (var context = CreateContext()) { - var actual = await context.Set().FromSqlRaw(NormalizeDelimetersInRawString(sql), city, contactTitle) + var actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString(sql), city, contactTitle) .ToArrayAsync(); Assert.Equal(3, actual.Length); @@ -253,7 +253,7 @@ public virtual async Task FromSqlRaw_queryable_with_parameters_cache_key_include city = "Madrid"; contactTitle = "Accounting Manager"; - actual = await context.Set().FromSqlRaw(NormalizeDelimetersInRawString(sql), city, contactTitle) + actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString(sql), city, contactTitle) .ToArrayAsync(); Assert.Equal(2, actual.Length); @@ -267,7 +267,7 @@ public virtual async Task FromSqlRaw_queryable_simple_as_no_tracking_not_compose { using (var context = CreateContext()) { - var actual = await context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) + var actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) .AsNoTracking() .ToArrayAsync(); @@ -281,7 +281,7 @@ public virtual async Task FromSqlRaw_queryable_simple_projection_not_composed() { using (var context = CreateContext()) { - var actual = await context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) + var actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) .Select( c => new { c.CustomerID, c.City }) .AsNoTracking() @@ -297,7 +297,7 @@ public virtual async Task FromSqlRaw_queryable_simple_include() { using (var context = CreateContext()) { - var actual = await context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) + var actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) .Include(c => c.Orders) .ToArrayAsync(); @@ -310,7 +310,7 @@ public virtual async Task FromSqlRaw_queryable_simple_composed_include() { using (var context = CreateContext()) { - var actual = await context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) + var actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) .Include(c => c.Orders) .Where(c => c.City == "London") .ToArrayAsync(); @@ -325,7 +325,7 @@ public virtual async Task FromSqlRaw_annotations_do_not_affect_successive_calls( using (var context = CreateContext()) { var actual = await context.Customers - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [ContactName] LIKE '%z%'")) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [ContactName] LIKE '%z%'")) .ToArrayAsync(); Assert.Equal(14, actual.Length); @@ -342,7 +342,7 @@ public virtual async Task FromSqlRaw_composed_with_nullable_predicate() { using (var context = CreateContext()) { - var actual = await context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) + var actual = await context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) .Where(c => c.ContactName == c.CompanyName) .ToArrayAsync(); @@ -400,11 +400,11 @@ public virtual async Task Include_closed_connection_opened_by_it_when_buffering( } } - private string NormalizeDelimetersInRawString(string sql) - => Fixture.TestStore.NormalizeDelimetersInRawString(sql); + private string NormalizeDelimitersInRawString(string sql) + => Fixture.TestStore.NormalizeDelimitersInRawString(sql); - private FormattableString NormalizeDelimetersInInterpolatedString(FormattableString sql) - => Fixture.TestStore.NormalizeDelimetersInInterpolatedString(sql); + private FormattableString NormalizeDelimitersInInterpolatedString(FormattableString sql) + => Fixture.TestStore.NormalizeDelimitersInInterpolatedString(sql); protected NorthwindContext CreateContext() => Fixture.CreateContext(); } diff --git a/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs index b2667c03de5..fc4e2df2515 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/FromSqlQueryTestBase.cs @@ -42,7 +42,7 @@ public virtual void Bad_data_error_handling_invalid_cast_key() Assert.Throws( () => context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( @"SELECT [ProductID] AS [ProductName], [ProductName] AS [ProductID], [SupplierID], [UnitPrice], [UnitsInStock], [Discontinued] FROM [Products]")) .ToList()).Message); @@ -59,7 +59,7 @@ public virtual void Bad_data_error_handling_invalid_cast() Assert.Throws( () => context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( @"SELECT [ProductID], [SupplierID] AS [UnitPrice], [ProductName], [SupplierID], [UnitsInStock], [Discontinued] FROM [Products]")) .ToList()).Message); @@ -76,7 +76,7 @@ public virtual void Bad_data_error_handling_invalid_cast_projection() Assert.Throws( () => context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( @"SELECT [ProductID], [SupplierID] AS [UnitPrice], [ProductName], [UnitsInStock], [Discontinued] FROM [Products]")) .Select(p => p.UnitPrice) @@ -95,7 +95,7 @@ public virtual void Bad_data_error_handling_invalid_cast_no_tracking() () => context.Set() .FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( @"SELECT [ProductID] AS [ProductName], [ProductName] AS [ProductID], [SupplierID], [UnitPrice], [UnitsInStock], [Discontinued] FROM [Products]")).AsNoTracking() .ToList()).Message); @@ -108,7 +108,7 @@ public virtual void Bad_data_error_handling_null() using (var context = CreateContext()) { context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( @"SELECT [ProductID], [ProductName], [SupplierID], [UnitPrice], [UnitsInStock], NULL AS [Discontinued] FROM [Products]")) .ToList(); @@ -117,7 +117,7 @@ public virtual void Bad_data_error_handling_null() Assert.Throws( () => context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( @"SELECT [ProductID], [ProductName], [SupplierID], [UnitPrice], [UnitsInStock], NULL AS [Discontinued] FROM [Products]")) .ToList()).Message); @@ -134,7 +134,7 @@ public virtual void Bad_data_error_handling_null_projection() Assert.Throws( () => context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( @"SELECT [ProductID], [ProductName], [SupplierID], [UnitPrice], [UnitsInStock], NULL AS [Discontinued] FROM [Products]")) .Select(p => p.Discontinued) @@ -153,7 +153,7 @@ public virtual void Bad_data_error_handling_null_no_tracking() () => context.Set() .FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( @"SELECT [ProductID], [ProductName], [SupplierID], [UnitPrice], [UnitsInStock], NULL AS [Discontinued] FROM [Products]")).AsNoTracking() .ToList()).Message); @@ -166,7 +166,7 @@ public virtual void FromSqlRaw_queryable_simple() using (var context = CreateContext()) { var actual = context.Set() - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [ContactName] LIKE '%z%'")) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [ContactName] LIKE '%z%'")) .ToArray(); Assert.Equal(14, actual.Length); @@ -180,7 +180,7 @@ public virtual void FromSqlRaw_queryable_simple_columns_out_of_order() using (var context = CreateContext()) { var actual = context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( "SELECT [Region], [PostalCode], [Phone], [Fax], [CustomerID], [Country], [ContactTitle], [ContactName], [CompanyName], [City], [Address] FROM [Customers]")) .ToArray(); @@ -195,7 +195,7 @@ public virtual void FromSqlRaw_queryable_simple_columns_out_of_order_and_extra_c using (var context = CreateContext()) { var actual = context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( "SELECT [Region], [PostalCode], [PostalCode] AS [Foo], [Phone], [Fax], [CustomerID], [Country], [ContactTitle], [ContactName], [CompanyName], [City], [Address] FROM [Customers]")) .ToArray(); @@ -213,7 +213,7 @@ public virtual void FromSqlRaw_queryable_simple_columns_out_of_order_and_not_eno RelationalStrings.FromSqlMissingColumn("Region"), Assert.Throws( () => context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( "SELECT [PostalCode], [Phone], [Fax], [CustomerID], [Country], [ContactTitle], [ContactName], [CompanyName], [City], [Address] FROM [Customers]")) .ToArray() ).Message); @@ -225,7 +225,7 @@ public virtual void FromSqlRaw_queryable_composed() { using (var context = CreateContext()) { - var actual = context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) + var actual = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) .Where(c => c.ContactName.Contains("z")) .ToArray(); @@ -239,7 +239,7 @@ public virtual void FromSqlRaw_queryable_composed_after_removing_whitespaces() using (var context = CreateContext()) { var actual = context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( _eol + " " + _eol + _eol + _eol + "SELECT" + _eol + "* FROM [Customers]")) .Where(c => c.ContactName.Contains("z")) .ToArray(); @@ -253,7 +253,7 @@ public virtual void FromSqlRaw_queryable_composed_compiled() { var query = EF.CompileQuery( (NorthwindContext context) => context.Set() - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) .Where(c => c.ContactName.Contains("z"))); using (var context = CreateContext()) @@ -270,7 +270,7 @@ public virtual void FromSqlRaw_queryable_composed_compiled_with_parameter() var query = EF.CompileQuery( (NorthwindContext context) => context.Set() .FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = {0}"), "CONSH") + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = {0}"), "CONSH") .Where(c => c.ContactName.Contains("z"))); using (var context = CreateContext()) @@ -287,7 +287,7 @@ public virtual void FromSqlRaw_queryable_composed_compiled_with_DbParameter() var query = EF.CompileQuery( (NorthwindContext context) => context.Set() .FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = @customer"), + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = @customer"), CreateDbParameter("customer", "CONSH")) .Where(c => c.ContactName.Contains("z"))); @@ -305,7 +305,7 @@ public virtual void FromSqlRaw_queryable_composed_compiled_with_nameless_DbParam var query = EF.CompileQuery( (NorthwindContext context) => context.Set() .FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = {0}"), + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = {0}"), CreateDbParameter(null, "CONSH")) .Where(c => c.ContactName.Contains("z"))); @@ -324,7 +324,7 @@ public virtual void FromSqlRaw_composed_contains() { var actual = (from c in context.Set() - where context.Orders.FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Orders]")) + where context.Orders.FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Orders]")) .Select(o => o.CustomerID) .Contains(c.CustomerID) select c) @@ -343,7 +343,7 @@ var actual = (from c in context.Set() where c.CustomerID == "ALFKI" - && context.Orders.FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Orders]")) + && context.Orders.FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Orders]")) .Select(o => o.CustomerID) .Contains(c.CustomerID) select c) @@ -359,8 +359,8 @@ public virtual void FromSqlRaw_queryable_multiple_composed() using (var context = CreateContext()) { var actual - = (from c in context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) - from o in context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Orders]")) + = (from c in context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) + from o in context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Orders]")) where c.CustomerID == o.CustomerID select new { c, o }) .ToArray(); @@ -378,9 +378,9 @@ public virtual void FromSqlRaw_queryable_multiple_composed_with_closure_paramete using (var context = CreateContext()) { var actual - = (from c in context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) + = (from c in context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) from o in context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), + NormalizeDelimitersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), startDate, endDate) where c.CustomerID == o.CustomerID @@ -402,9 +402,9 @@ public virtual void FromSqlRaw_queryable_multiple_composed_with_parameters_and_c { var actual = (from c in context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) from o in context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), + NormalizeDelimitersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), startDate, endDate) where c.CustomerID == o.CustomerID @@ -419,9 +419,9 @@ from o in context.Set().FromSqlRaw( actual = (from c in context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) from o in context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), + NormalizeDelimitersInRawString("SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {0} AND {1}"), startDate, endDate) where c.CustomerID == o.CustomerID @@ -438,7 +438,7 @@ public virtual void FromSqlRaw_queryable_multiple_line_query() using (var context = CreateContext()) { var actual = context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( @"SELECT * FROM [Customers] WHERE [City] = 'London'")) @@ -455,7 +455,7 @@ public virtual void FromSqlRaw_queryable_composed_multiple_line_query() using (var context = CreateContext()) { var actual = context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( @"SELECT * FROM [Customers]")) .Where(c => c.City == "London") @@ -475,7 +475,7 @@ public virtual void FromSqlRaw_queryable_with_parameters() using (var context = CreateContext()) { var actual = context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"), city, + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"), city, contactTitle) .ToArray(); @@ -491,7 +491,7 @@ public virtual void FromSqlRaw_queryable_with_parameters_inline() using (var context = CreateContext()) { var actual = context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"), "London", + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = {1}"), "London", "Sales Representative") .ToArray(); @@ -510,7 +510,7 @@ public virtual void FromSqlInterpolated_queryable_with_parameters_interpolated() using (var context = CreateContext()) { var actual = context.Set().FromSqlInterpolated( - NormalizeDelimetersInInterpolatedString( + NormalizeDelimitersInInterpolatedString( $"SELECT * FROM [Customers] WHERE [City] = {city} AND [ContactTitle] = {contactTitle}")) .ToArray(); @@ -526,7 +526,7 @@ public virtual void FromSqlInterpolated_queryable_with_parameters_inline_interpo using (var context = CreateContext()) { var actual = context.Set().FromSqlInterpolated( - NormalizeDelimetersInInterpolatedString( + NormalizeDelimitersInInterpolatedString( $"SELECT * FROM [Customers] WHERE [City] = {"London"} AND [ContactTitle] = {"Sales Representative"}")) .ToArray(); @@ -547,9 +547,9 @@ public virtual void FromSqlInterpolated_queryable_multiple_composed_with_paramet { var actual = (from c in context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) from o in context.Set().FromSqlInterpolated( - NormalizeDelimetersInInterpolatedString( + NormalizeDelimitersInInterpolatedString( $"SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {startDate} AND {endDate}")) where c.CustomerID == o.CustomerID select new { c, o }) @@ -563,9 +563,9 @@ from o in context.Set().FromSqlInterpolated( actual = (from c in context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) from o in context.Set().FromSqlInterpolated( - NormalizeDelimetersInInterpolatedString( + NormalizeDelimitersInInterpolatedString( $"SELECT * FROM [Orders] WHERE [OrderDate] BETWEEN {startDate} AND {endDate}")) where c.CustomerID == o.CustomerID select new { c, o }) @@ -583,7 +583,7 @@ public virtual void FromSqlRaw_queryable_with_null_parameter() using (var context = CreateContext()) { var actual = context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( // ReSharper disable once ExpressionIsAlwaysNull "SELECT * FROM [Employees] WHERE [ReportsTo] = {0} OR ([ReportsTo] IS NULL AND {0} IS NULL)"), reportsTo) .ToArray(); @@ -601,7 +601,7 @@ public virtual void FromSqlRaw_queryable_with_parameters_and_closure() using (var context = CreateContext()) { var actual = context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = {0}"), city) .Where(c => c.ContactTitle == contactTitle) .ToArray(); @@ -617,14 +617,14 @@ public virtual void FromSqlRaw_queryable_simple_cache_key_includes_query_string( using (var context = CreateContext()) { var actual = context.Set() - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = 'London'")) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'London'")) .ToArray(); Assert.Equal(6, actual.Length); Assert.True(actual.All(c => c.City == "London")); actual = context.Set() - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = 'Seattle'")) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'Seattle'")) .ToArray(); Assert.Single(actual); @@ -641,7 +641,7 @@ public virtual void FromSqlRaw_queryable_with_parameters_cache_key_includes_para using (var context = CreateContext()) { - var actual = context.Set().FromSqlRaw(NormalizeDelimetersInRawString(sql), city, contactTitle) + var actual = context.Set().FromSqlRaw(NormalizeDelimitersInRawString(sql), city, contactTitle) .ToArray(); Assert.Equal(3, actual.Length); @@ -651,7 +651,7 @@ public virtual void FromSqlRaw_queryable_with_parameters_cache_key_includes_para city = "Madrid"; contactTitle = "Accounting Manager"; - actual = context.Set().FromSqlRaw(NormalizeDelimetersInRawString(sql), city, contactTitle) + actual = context.Set().FromSqlRaw(NormalizeDelimitersInRawString(sql), city, contactTitle) .ToArray(); Assert.Equal(2, actual.Length); @@ -665,7 +665,7 @@ public virtual void FromSqlRaw_queryable_simple_as_no_tracking_not_composed() { using (var context = CreateContext()) { - var actual = context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) + var actual = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) .AsNoTracking() .ToArray(); @@ -681,7 +681,7 @@ public virtual void FromSqlRaw_queryable_simple_projection_composed() { var boolMapping = (RelationalTypeMapping)context.GetService().FindMapping(typeof(bool)); var actual = context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( @"SELECT * FROM [Products] WHERE [Discontinued] <> " @@ -700,7 +700,7 @@ public virtual void FromSqlRaw_queryable_simple_include() { using (var context = CreateContext()) { - var actual = context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) + var actual = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) .Include(c => c.Orders) .ToArray(); @@ -713,7 +713,7 @@ public virtual void FromSqlRaw_queryable_simple_composed_include() { using (var context = CreateContext()) { - var actual = context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) + var actual = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) .Include(c => c.Orders) .Where(c => c.City == "London") .ToArray(); @@ -728,7 +728,7 @@ public virtual void FromSqlRaw_annotations_do_not_affect_successive_calls() using (var context = CreateContext()) { var actual = context.Customers - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [ContactName] LIKE '%z%'")) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [ContactName] LIKE '%z%'")) .ToArray(); Assert.Equal(14, actual.Length); @@ -745,7 +745,7 @@ public virtual void FromSqlRaw_composed_with_nullable_predicate() { using (var context = CreateContext()) { - var actual = context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers]")) + var actual = context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers]")) .Where(c => c.ContactName == c.CompanyName) .ToArray(); @@ -761,7 +761,7 @@ public virtual void FromSqlRaw_with_dbParameter() var parameter = CreateDbParameter("@city", "London"); var actual = context.Customers.FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = @city"), parameter) + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = @city"), parameter) .ToArray(); Assert.Equal(6, actual.Length); @@ -777,7 +777,7 @@ public virtual void FromSqlRaw_with_dbParameter_without_name_prefix() var parameter = CreateDbParameter("city", "London"); var actual = context.Customers.FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = @city"), parameter) + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = @city"), parameter) .ToArray(); Assert.Equal(6, actual.Length); @@ -796,7 +796,7 @@ public virtual void FromSqlRaw_with_dbParameter_mixed() var titleParameter = CreateDbParameter("@title", title); var actual = context.Customers.FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( "SELECT * FROM [Customers] WHERE [City] = {0} AND [ContactTitle] = @title"), city, titleParameter) .ToArray(); @@ -807,7 +807,7 @@ public virtual void FromSqlRaw_with_dbParameter_mixed() var cityParameter = CreateDbParameter("@city", city); actual = context.Customers.FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( "SELECT * FROM [Customers] WHERE [City] = @city AND [ContactTitle] = {1}"), cityParameter, title) .ToArray(); @@ -855,7 +855,7 @@ public virtual void FromSqlRaw_with_db_parameters_called_multiple_times() var parameter = CreateDbParameter("@id", "ALFKI"); var query = context.Customers.FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = @id"), parameter); + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = @id"), parameter); // ReSharper disable PossibleMultipleEnumeration var result1 = query.ToList(); @@ -875,9 +875,9 @@ public virtual void FromSqlRaw_with_SelectMany_and_include() using (var context = CreateContext()) { var query = from c1 in context.Set() - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = 'ALFKI'")) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = 'ALFKI'")) from c2 in context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = 'AROUT'")) + NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = 'AROUT'")) .Include(c => c.Orders) select new { c1, c2 }; @@ -904,9 +904,9 @@ public virtual void FromSqlRaw_with_join_and_include() using (var context = CreateContext()) { var query = from c in context.Set() - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = 'ALFKI'")) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [CustomerID] = 'ALFKI'")) join o in context.Set().FromSqlRaw( - NormalizeDelimetersInRawString("SELECT * FROM [Orders] WHERE [OrderID] <> 1")) + NormalizeDelimitersInRawString("SELECT * FROM [Orders] WHERE [OrderID] <> 1")) .Include(o => o.OrderDetails) on c.CustomerID equals o.CustomerID select new { c, o }; @@ -952,7 +952,7 @@ public virtual void FromSqlInterpolated_with_inlined_db_parameter() var actual = context.Customers .FromSqlInterpolated( - NormalizeDelimetersInInterpolatedString($"SELECT * FROM [Customers] WHERE [CustomerID] = {parameter}")) + NormalizeDelimitersInInterpolatedString($"SELECT * FROM [Customers] WHERE [CustomerID] = {parameter}")) .ToList(); Assert.Single(actual); @@ -969,7 +969,7 @@ public virtual void FromSqlInterpolated_with_inlined_db_parameter_without_name_p var actual = context.Customers .FromSqlInterpolated( - NormalizeDelimetersInInterpolatedString($"SELECT * FROM [Customers] WHERE [CustomerID] = {parameter}")) + NormalizeDelimitersInInterpolatedString($"SELECT * FROM [Customers] WHERE [CustomerID] = {parameter}")) .ToList(); Assert.Single(actual); @@ -986,7 +986,7 @@ public virtual void FromSqlInterpolated_parameterization_issue_12213() var max = 10400; var query1 = context.Orders - .FromSqlInterpolated(NormalizeDelimetersInInterpolatedString($"SELECT * FROM [Orders] WHERE [OrderID] >= {min}")) + .FromSqlInterpolated(NormalizeDelimitersInInterpolatedString($"SELECT * FROM [Orders] WHERE [OrderID] >= {min}")) .Select(i => i.OrderID); query1.ToList(); @@ -1000,7 +1000,7 @@ public virtual void FromSqlInterpolated_parameterization_issue_12213() o => o.OrderID <= max && context.Orders .FromSqlInterpolated( - NormalizeDelimetersInInterpolatedString($"SELECT * FROM [Orders] WHERE [OrderID] >= {min}")) + NormalizeDelimitersInInterpolatedString($"SELECT * FROM [Orders] WHERE [OrderID] >= {min}")) .Select(i => i.OrderID) .Contains(o.OrderID)) .Select(o => o.OrderID); @@ -1016,7 +1016,7 @@ public virtual void FromSqlRaw_does_not_parameterize_interpolated_string() var tableName = "Orders"; var max = 10250; var query = context.Orders.FromSqlRaw( - NormalizeDelimetersInRawString($"SELECT * FROM [{tableName}] WHERE [OrderID] < {{0}}"), max) + NormalizeDelimitersInRawString($"SELECT * FROM [{tableName}] WHERE [OrderID] < {{0}}"), max) .ToList(); Assert.Equal(2, query.Count); @@ -1029,7 +1029,7 @@ public virtual void Entity_equality_through_fromsql() using (var context = CreateContext()) { var actual = context.Set() - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Orders]")) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Orders]")) .Where(o => o.Customer == new Customer { CustomerID = "VINET" }) .ToArray(); @@ -1043,20 +1043,20 @@ public virtual void FromSqlRaw_with_set_operation() using var context = CreateContext(); var actual = context.Set() - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = 'London'")) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'London'")) .Concat( context.Set() - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Customers] WHERE [City] = 'Berlin'"))) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Customers] WHERE [City] = 'Berlin'"))) .ToArray(); Assert.Equal(7, actual.Length); } - protected string NormalizeDelimetersInRawString(string sql) - => Fixture.TestStore.NormalizeDelimetersInRawString(sql); + protected string NormalizeDelimitersInRawString(string sql) + => Fixture.TestStore.NormalizeDelimitersInRawString(sql); - protected FormattableString NormalizeDelimetersInInterpolatedString(FormattableString sql) - => Fixture.TestStore.NormalizeDelimetersInInterpolatedString(sql); + protected FormattableString NormalizeDelimitersInInterpolatedString(FormattableString sql) + => Fixture.TestStore.NormalizeDelimitersInInterpolatedString(sql); protected abstract DbParameter CreateDbParameter(string name, object value); diff --git a/test/EFCore.Relational.Specification.Tests/Query/FromSqlSprocQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/FromSqlSprocQueryTestBase.cs index ad293f32261..33ed6b13d65 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/FromSqlSprocQueryTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/FromSqlSprocQueryTestBase.cs @@ -370,7 +370,7 @@ public virtual async Task From_sql_queryable_stored_procedure_and_select(bool as var query = from mep in context.Set() .FromSqlRaw(TenMostExpensiveProductsSproc, GetTenMostExpensiveProductsParameters()) from p in context.Set() - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Products]")) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Products]")) where mep.TenMostExpensiveProducts == p.ProductName select new { mep, p }; @@ -390,7 +390,7 @@ public virtual async Task From_sql_queryable_stored_procedure_and_select_on_clie var query1 = context.Set() .FromSqlRaw(TenMostExpensiveProductsSproc, GetTenMostExpensiveProductsParameters()); var query2 = context.Set() - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Products]")); + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Products]")); var results1 = async ? await query1.ToListAsync() : query1.ToList(); var results2 = async ? await query2.ToListAsync() : query2.ToList(); @@ -409,7 +409,7 @@ from p in results2 public virtual async Task From_sql_queryable_select_and_stored_procedure(bool async) { using var context = CreateContext(); - var query = from p in context.Set().FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Products]")) + var query = from p in context.Set().FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Products]")) from mep in context.Set() .FromSqlRaw(TenMostExpensiveProductsSproc, GetTenMostExpensiveProductsParameters()) where mep.TenMostExpensiveProducts == p.ProductName @@ -430,7 +430,7 @@ public virtual async Task From_sql_queryable_select_and_stored_procedure_on_clie using var context = CreateContext(); var query1 = context.Set() - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Products]")); + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Products]")); var query2 = context.Set() .FromSqlRaw(TenMostExpensiveProductsSproc, GetTenMostExpensiveProductsParameters()); @@ -445,8 +445,8 @@ from mep in results2 Assert.Equal(10, actual.Length); } - private string NormalizeDelimetersInRawString(string sql) - => Fixture.TestStore.NormalizeDelimetersInRawString(sql); + private string NormalizeDelimitersInRawString(string sql) + => Fixture.TestStore.NormalizeDelimitersInRawString(sql); protected virtual object[] GetTenMostExpensiveProductsParameters() => Array.Empty(); diff --git a/test/EFCore.Relational.Specification.Tests/Query/GearsOfWarFromSqlQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/GearsOfWarFromSqlQueryTestBase.cs index c23cc5c575f..fc550c6b24f 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/GearsOfWarFromSqlQueryTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/GearsOfWarFromSqlQueryTestBase.cs @@ -22,7 +22,7 @@ public virtual void From_sql_queryable_simple_columns_out_of_order() using (var context = CreateContext()) { var actual = context.Set().FromSqlRaw( - NormalizeDelimetersInRawString( + NormalizeDelimitersInRawString( "SELECT [Id], [Name], [IsAutomatic], [AmmunitionType], [OwnerFullName], [SynergyWithId] FROM [Weapons] ORDER BY [Name]")) .ToArray(); @@ -35,11 +35,11 @@ public virtual void From_sql_queryable_simple_columns_out_of_order() } } - private string NormalizeDelimetersInRawString(string sql) - => Fixture.TestStore.NormalizeDelimetersInRawString(sql); + private string NormalizeDelimitersInRawString(string sql) + => Fixture.TestStore.NormalizeDelimitersInRawString(sql); - private FormattableString NormalizeDelimetersInInterpolatedString(FormattableString sql) - => Fixture.TestStore.NormalizeDelimetersInInterpolatedString(sql); + private FormattableString NormalizeDelimitersInInterpolatedString(FormattableString sql) + => Fixture.TestStore.NormalizeDelimitersInInterpolatedString(sql); protected GearsOfWarContext CreateContext() => Fixture.CreateContext(); diff --git a/test/EFCore.Relational.Specification.Tests/Query/InheritanceRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/InheritanceRelationalTestBase.cs index 797dddd616b..eb742f683f2 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/InheritanceRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/InheritanceRelationalTestBase.cs @@ -23,7 +23,7 @@ public virtual void FromSql_on_root() { using (var context = CreateContext()) { - context.Set().FromSqlRaw(NormalizeDelimetersInRawString("select * from [Animal]")).ToList(); + context.Set().FromSqlRaw(NormalizeDelimitersInRawString("select * from [Animal]")).ToList(); } } @@ -32,14 +32,14 @@ public virtual void FromSql_on_derived() { using (var context = CreateContext()) { - context.Set().FromSqlRaw(NormalizeDelimetersInRawString("select * from [Animal]")).ToList(); + context.Set().FromSqlRaw(NormalizeDelimitersInRawString("select * from [Animal]")).ToList(); } } - private string NormalizeDelimetersInRawString(string sql) - => ((RelationalTestStore)Fixture.TestStore).NormalizeDelimetersInRawString(sql); + private string NormalizeDelimitersInRawString(string sql) + => ((RelationalTestStore)Fixture.TestStore).NormalizeDelimitersInRawString(sql); - private FormattableString NormalizeDelimetersInInterpolatedString(FormattableString sql) - => ((RelationalTestStore)Fixture.TestStore).NormalizeDelimetersInInterpolatedString(sql); + private FormattableString NormalizeDelimitersInInterpolatedString(FormattableString sql) + => ((RelationalTestStore)Fixture.TestStore).NormalizeDelimitersInInterpolatedString(sql); } } diff --git a/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs index 8470e2a762d..4887d1391d1 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs @@ -745,7 +745,7 @@ public virtual void From_sql_composed_with_relational_null_comparison() using (var context = CreateContext(useRelationalNulls: true)) { var actual = context.Entities1 - .FromSqlRaw(NormalizeDelimetersInRawString("SELECT * FROM [Entities1]")) + .FromSqlRaw(NormalizeDelimitersInRawString("SELECT * FROM [Entities1]")) .Where(c => c.StringA == c.StringB) .ToArray(); @@ -1065,11 +1065,11 @@ protected static TResult Maybe(object caller, Func expression) return caller == null ? null : expression(); } - private string NormalizeDelimetersInRawString(string sql) - => Fixture.TestStore.NormalizeDelimetersInRawString(sql); + private string NormalizeDelimitersInRawString(string sql) + => Fixture.TestStore.NormalizeDelimitersInRawString(sql); private FormattableString NormalizeDelimetersInInterpolatedString(FormattableString sql) - => Fixture.TestStore.NormalizeDelimetersInInterpolatedString(sql); + => Fixture.TestStore.NormalizeDelimitersInInterpolatedString(sql); protected abstract NullSemanticsContext CreateContext(bool useRelationalNulls = false); diff --git a/test/EFCore.Relational.Specification.Tests/Query/QueryNoClientEvalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/QueryNoClientEvalTestBase.cs index 8ef7b5112d8..451f5c30918 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/QueryNoClientEvalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/QueryNoClientEvalTestBase.cs @@ -80,7 +80,7 @@ public virtual void Throws_when_from_sql_composed() { AssertTranslationFailed( () => context.Customers - .FromSqlRaw(NormalizeDelimetersInRawString("select * from [Customers]")) + .FromSqlRaw(NormalizeDelimitersInRawString("select * from [Customers]")) .Where(c => c.IsLondon) .ToList()); } @@ -93,7 +93,7 @@ public virtual void Doesnt_throw_when_from_sql_not_composed() { var customers = context.Customers - .FromSqlRaw(NormalizeDelimetersInRawString("select * from [Customers]")) + .FromSqlRaw(NormalizeDelimitersInRawString("select * from [Customers]")) .ToList(); Assert.Equal(91, customers.Count); @@ -232,8 +232,8 @@ public virtual void Throws_when_single_or_default() } } - private string NormalizeDelimetersInRawString(string sql) - => Fixture.TestStore.NormalizeDelimetersInRawString(sql); + private string NormalizeDelimitersInRawString(string sql) + => Fixture.TestStore.NormalizeDelimitersInRawString(sql); private void AssertTranslationFailed(Action testCode) { diff --git a/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalDatabaseCleaner.cs b/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalDatabaseCleaner.cs index 85b981d5e87..709f36b83fb 100644 --- a/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalDatabaseCleaner.cs +++ b/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalDatabaseCleaner.cs @@ -129,7 +129,7 @@ private static void ExecuteScript(IRelationalConnection connection, IRawSqlComma } sqlBuilder.Build(batches[i]) - .ExecuteNonQuery(new RelationalCommandParameterObject(connection, null, null, null)); + .ExecuteNonQuery(new RelationalCommandParameterObject(connection, null, null, null, null)); } } diff --git a/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalTestStore.cs b/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalTestStore.cs index f458093cd1c..eceb4d9a564 100644 --- a/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalTestStore.cs +++ b/test/EFCore.Relational.Specification.Tests/TestUtilities/RelationalTestStore.cs @@ -43,14 +43,14 @@ public override void Dispose() base.Dispose(); } - public virtual string NormalizeDelimetersInRawString(string sql) - => sql.Replace("[", OpenDelimeter).Replace("]", CloseDelimeter); + public virtual string NormalizeDelimitersInRawString(string sql) + => sql.Replace("[", OpenDelimiter).Replace("]", CloseDelimiter); - public virtual FormattableString NormalizeDelimetersInInterpolatedString(FormattableString sql) - => new TestFormattableString(NormalizeDelimetersInRawString(sql.Format), sql.GetArguments()); + public virtual FormattableString NormalizeDelimitersInInterpolatedString(FormattableString sql) + => new TestFormattableString(NormalizeDelimitersInRawString(sql.Format), sql.GetArguments()); - protected virtual string OpenDelimeter => "\""; + protected virtual string OpenDelimiter => "\""; - protected virtual string CloseDelimeter => "\""; + protected virtual string CloseDelimiter => "\""; } } diff --git a/test/EFCore.Relational.Tests/Query/Internal/BufferedDataReaderTest.cs b/test/EFCore.Relational.Tests/Query/Internal/BufferedDataReaderTest.cs new file mode 100644 index 00000000000..825d3cf2e6e --- /dev/null +++ b/test/EFCore.Relational.Tests/Query/Internal/BufferedDataReaderTest.cs @@ -0,0 +1,217 @@ +// 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.Data.Common; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider; +using Xunit; + +// ReSharper disable InconsistentNaming +namespace Microsoft.EntityFrameworkCore.Query.Internal +{ + public class BufferedDataReaderTest + { + public static IEnumerable IsAsyncData = new[] { new object[] { false }, new object[] { true } }; + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public async Task Metadata_methods_return_expected_results(bool async) + { + var reader = new FakeDbDataReader(new[] { "columnName" }, new[] { new[] { new object() }, new[] { new object() } }); + var columns = new ReaderColumn[] { new ReaderColumn(true, null, (r, _) => r.GetValue(0)) }; + var bufferedDataReader = new BufferedDataReader(reader); + if (async) + { + await bufferedDataReader.InitializeAsync(columns, CancellationToken.None); + } + else + { + bufferedDataReader.Initialize(columns); + } + + Assert.Equal(1, bufferedDataReader.FieldCount); + Assert.Equal(0, bufferedDataReader.GetOrdinal("columnName")); + Assert.Equal(typeof(object).Name, bufferedDataReader.GetDataTypeName(0)); + Assert.Equal(typeof(object), bufferedDataReader.GetFieldType(0)); + Assert.Equal("columnName", bufferedDataReader.GetName(0)); + Assert.Equal(2, bufferedDataReader.RecordsAffected); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public async Task Manipulation_methods_perform_expected_actions(bool async) + { + var reader = new FakeDbDataReader( + new[] { "id", "name" }, + new List> { new[] { new object[] { 1, "a" } }, new object[0][] }); + var columns = new ReaderColumn[] + { + new ReaderColumn(false, null, (r, _) => r.GetInt32(0)), new ReaderColumn(true, null, (r, _) => r.GetValue(1)) + }; + + var bufferedDataReader = new BufferedDataReader(reader); + + Assert.False(bufferedDataReader.IsClosed); + if (async) + { + await bufferedDataReader.InitializeAsync(columns, CancellationToken.None); + } + else + { + bufferedDataReader.Initialize(columns); + } + + Assert.False(bufferedDataReader.IsClosed); + + Assert.True(bufferedDataReader.HasRows); + + if (async) + { + Assert.True(await bufferedDataReader.ReadAsync()); + Assert.False(await bufferedDataReader.ReadAsync()); + } + else + { + Assert.True(bufferedDataReader.Read()); + Assert.False(bufferedDataReader.Read()); + } + + Assert.True(bufferedDataReader.HasRows); + + if (async) + { + Assert.True(await bufferedDataReader.NextResultAsync()); + } + else + { + Assert.True(bufferedDataReader.NextResult()); + } + + Assert.False(bufferedDataReader.HasRows); + + if (async) + { + Assert.False(await bufferedDataReader.ReadAsync()); + Assert.False(await bufferedDataReader.NextResultAsync()); + } + else + { + Assert.False(bufferedDataReader.Read()); + Assert.False(bufferedDataReader.NextResult()); + } + + Assert.False(bufferedDataReader.IsClosed); + bufferedDataReader.Close(); + Assert.True(bufferedDataReader.IsClosed); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public async Task Initialize_is_idempotent(bool isAsync) + { + var reader = new FakeDbDataReader(new[] { "name" }, new[] { new[] { new object() } }); + var columns = new ReaderColumn[] { new ReaderColumn(true, null, (r, _) => r.GetValue(0)) }; + var bufferedReader = new BufferedDataReader(reader); + + Assert.False(reader.IsClosed); + if (isAsync) + { + await bufferedReader.InitializeAsync(columns, CancellationToken.None); + } + else + { + bufferedReader.Initialize(columns); + } + + Assert.True(reader.IsClosed); + + if (isAsync) + { + await bufferedReader.InitializeAsync(columns, CancellationToken.None); + } + else + { + bufferedReader.Initialize(columns); + } + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public async Task Data_methods_return_expected_results(bool async) + { + await Verify_get_method_returns_supplied_value(true, async); + await Verify_get_method_returns_supplied_value((byte)1, async); + await Verify_get_method_returns_supplied_value((short)1, async); + await Verify_get_method_returns_supplied_value(1, async); + await Verify_get_method_returns_supplied_value(1L, async); + await Verify_get_method_returns_supplied_value(1F, async); + await Verify_get_method_returns_supplied_value(1D, async); + await Verify_get_method_returns_supplied_value(1M, async); + await Verify_get_method_returns_supplied_value('a', async); + await Verify_get_method_returns_supplied_value("a", async); + await Verify_get_method_returns_supplied_value(DateTime.Now, async); + await Verify_get_method_returns_supplied_value(Guid.NewGuid(), async); + var obj = new object(); + await Verify_method_result(r => r.GetValue(0), async, obj, new[] { obj }); + await Verify_method_result(r => r.GetFieldValue(0), async, obj, new[] { obj }); + await Verify_method_result(r => r.GetFieldValueAsync(0).Result, async, obj, new[] { obj }); + await Verify_method_result(r => r.IsDBNull(0), async, true, new object[] { DBNull.Value }); + await Verify_method_result(r => r.IsDBNull(0), async, false, new object[] { true }); + await Verify_method_result(r => r.IsDBNullAsync(0).Result, async, true, new object[] { DBNull.Value }); + await Verify_method_result(r => r.IsDBNullAsync(0).Result, async, false, new object[] { true }); + + await Assert.ThrowsAsync( + () => Verify_method_result(r => r.GetBytes(0, 0, new byte[0], 0, 0), async, 0, new object[] { 1L })); + await Assert.ThrowsAsync( + () => Verify_method_result(r => r.GetChars(0, 0, new char[0], 0, 0), async, 0, new object[] { 1L })); + } + + private async Task Verify_method_result( + Func method, bool async, T expectedResult, + params object[][] dataReaderContents) + { + var reader = new FakeDbDataReader(new[] { "name" }, dataReaderContents); + var columnType = typeof(T); + if (!columnType.IsValueType) + { + columnType = typeof(object); + } + + var columns = new[] + { + ReaderColumn.Create(columnType, true, null, (Func)((r, _) => r.GetFieldValue(0))) + }; + + var bufferedReader = new BufferedDataReader(reader); + if (async) + { + await bufferedReader.InitializeAsync(columns, CancellationToken.None); + + Assert.True(await bufferedReader.ReadAsync()); + } + else + { + bufferedReader.Initialize(columns); + + Assert.True(bufferedReader.Read()); + } + + Assert.Equal(expectedResult, method(bufferedReader)); + } + + private Task Verify_get_method_returns_supplied_value(T value, bool async) + { + // use the specific reader.GetXXX method + var readerMethod = GetReaderMethod(typeof(T)); + return Verify_method_result( + r => (T)readerMethod.Invoke(r, new object[] { 0 }), async, value, new object[] { value }); + } + + private static MethodInfo GetReaderMethod(Type type) => RelationalTypeMapping.GetDataReaderMethod(type); + } +} diff --git a/test/EFCore.Relational.Tests/Storage/RelationalCommandTest.cs b/test/EFCore.Relational.Tests/Storage/RelationalCommandTest.cs index fe76bc30dd8..de1a836b2e6 100644 --- a/test/EFCore.Relational.Tests/Storage/RelationalCommandTest.cs +++ b/test/EFCore.Relational.Tests/Storage/RelationalCommandTest.cs @@ -44,7 +44,7 @@ public void Configures_DbCommand() var relationalCommand = CreateRelationalCommand(commandText: "CommandText"); relationalCommand.ExecuteNonQuery( - new RelationalCommandParameterObject(fakeConnection, null, null, null)); + new RelationalCommandParameterObject(fakeConnection, null, null, null, null)); Assert.Equal(1, fakeConnection.DbConnections.Count); Assert.Equal(1, fakeConnection.DbConnections[0].DbCommands.Count); @@ -66,7 +66,7 @@ public void Configures_DbCommand_with_transaction() var relationalCommand = CreateRelationalCommand(); relationalCommand.ExecuteNonQuery( - new RelationalCommandParameterObject(fakeConnection, null, null, null)); + new RelationalCommandParameterObject(fakeConnection, null, null, null, null)); Assert.Equal(1, fakeConnection.DbConnections.Count); Assert.Equal(1, fakeConnection.DbConnections[0].DbCommands.Count); @@ -88,7 +88,7 @@ public void Configures_DbCommand_with_timeout() var relationalCommand = CreateRelationalCommand(); relationalCommand.ExecuteNonQuery( - new RelationalCommandParameterObject(fakeConnection, null, null, null)); + new RelationalCommandParameterObject(fakeConnection, null, null, null, null)); Assert.Equal(1, fakeConnection.DbConnections.Count); Assert.Equal(1, fakeConnection.DbConnections[0].DbCommands.Count); @@ -122,7 +122,7 @@ public void Can_ExecuteNonQuery() var result = relationalCommand.ExecuteNonQuery( new RelationalCommandParameterObject( - new FakeRelationalConnection(options), null, null, null)); + new FakeRelationalConnection(options), null, null, null, null)); Assert.Equal(1, result); @@ -162,7 +162,7 @@ public virtual async Task Can_ExecuteNonQueryAsync() var result = await relationalCommand.ExecuteNonQueryAsync( new RelationalCommandParameterObject( - new FakeRelationalConnection(options), null, null, null)); + new FakeRelationalConnection(options), null, null, null, null)); Assert.Equal(1, result); @@ -202,7 +202,7 @@ public void Can_ExecuteScalar() var result = (string)relationalCommand.ExecuteScalar( new RelationalCommandParameterObject( - new FakeRelationalConnection(options), null, null, null)); + new FakeRelationalConnection(options), null, null, null, null)); Assert.Equal("ExecuteScalar Result", result); @@ -242,7 +242,7 @@ public async Task Can_ExecuteScalarAsync() var result = (string)await relationalCommand.ExecuteScalarAsync( new RelationalCommandParameterObject( - new FakeRelationalConnection(options), null, null, null)); + new FakeRelationalConnection(options), null, null, null, null)); Assert.Equal("ExecuteScalar Result", result); @@ -284,7 +284,7 @@ public void Can_ExecuteReader() var result = relationalCommand.ExecuteReader( new RelationalCommandParameterObject( - new FakeRelationalConnection(options), null, null, null)); + new FakeRelationalConnection(options), null, null, null, null)); Assert.Same(dbDataReader, result.DbDataReader); Assert.Equal(0, fakeDbConnection.CloseCount); @@ -333,7 +333,7 @@ public async Task Can_ExecuteReaderAsync() var result = await relationalCommand.ExecuteReaderAsync( new RelationalCommandParameterObject( - new FakeRelationalConnection(options), null, null, null)); + new FakeRelationalConnection(options), null, null, null, null)); Assert.Same(dbDataReader, result.DbDataReader); Assert.Equal(0, fakeDbConnection.CloseCount); @@ -363,42 +363,42 @@ public static TheoryData CommandActions new CommandAction( (connection, command, parameterValues, logger) => command.ExecuteNonQuery( - new RelationalCommandParameterObject(connection, parameterValues, null, logger))), + new RelationalCommandParameterObject(connection, parameterValues, null, null, logger))), DbCommandMethod.ExecuteNonQuery, false }, { new CommandAction( (connection, command, parameterValues, logger) => command.ExecuteScalar( - new RelationalCommandParameterObject(connection, parameterValues, null, logger))), + new RelationalCommandParameterObject(connection, parameterValues, null, null, logger))), DbCommandMethod.ExecuteScalar, false }, { new CommandAction( (connection, command, parameterValues, logger) => command.ExecuteReader( - new RelationalCommandParameterObject(connection, parameterValues, null, logger))), + new RelationalCommandParameterObject(connection, parameterValues, null, null, logger))), DbCommandMethod.ExecuteReader, false }, { new CommandFunc( (connection, command, parameterValues, logger) => command.ExecuteNonQueryAsync( - new RelationalCommandParameterObject(connection, parameterValues, null, logger))), + new RelationalCommandParameterObject(connection, parameterValues, null, null, logger))), DbCommandMethod.ExecuteNonQuery, true }, { new CommandFunc( (connection, command, parameterValues, logger) => command.ExecuteScalarAsync( - new RelationalCommandParameterObject(connection, parameterValues, null, logger))), + new RelationalCommandParameterObject(connection, parameterValues, null, null, logger))), DbCommandMethod.ExecuteScalar, true }, { new CommandFunc( (connection, command, parameterValues, logger) => command.ExecuteReaderAsync( - new RelationalCommandParameterObject(connection, parameterValues, null, logger))), + new RelationalCommandParameterObject(connection, parameterValues, null, null, logger))), DbCommandMethod.ExecuteReader, true } }; diff --git a/test/EFCore.Relational.Tests/TestUtilities/FakeProvider/FakeDbDataReader.cs b/test/EFCore.Relational.Tests/TestUtilities/FakeProvider/FakeDbDataReader.cs index cf430d3b8d9..48957c7523f 100644 --- a/test/EFCore.Relational.Tests/TestUtilities/FakeProvider/FakeDbDataReader.cs +++ b/test/EFCore.Relational.Tests/TestUtilities/FakeProvider/FakeDbDataReader.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Collections.Generic; using System.Data.Common; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -13,15 +14,26 @@ namespace Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider public class FakeDbDataReader : DbDataReader { private readonly string[] _columnNames; - private readonly IList _results; + private IList _results; + private readonly IList> _resultSets; + private int _currentResultSet; private object[] _currentRow; private int _rowIndex; + private bool _closed; public FakeDbDataReader(string[] columnNames = null, IList results = null) { _columnNames = columnNames ?? Array.Empty(); _results = results ?? new List(); + _resultSets = new List> { _results }; + } + + public FakeDbDataReader(string[] columnNames, IList> resultSets) + { + _columnNames = columnNames ?? Array.Empty(); + _resultSets = resultSets ?? new List> { new List() }; + _results = _resultSets[0]; } public override bool Read() @@ -51,6 +63,7 @@ public override Task ReadAsync(CancellationToken cancellationToken) public override void Close() { CloseCount++; + _closed = true; } public int DisposeCount { get; private set; } @@ -63,6 +76,8 @@ protected override void Dispose(bool disposing) base.Dispose(true); } + + _closed = true; } public override int FieldCount => _columnNames.Length; @@ -88,11 +103,11 @@ public override int GetInt32(int ordinal) public override int Depth => throw new NotImplementedException(); - public override bool HasRows => throw new NotImplementedException(); + public override bool HasRows => _results.Count != 0; - public override bool IsClosed => throw new NotImplementedException(); + public override bool IsClosed => _closed; - public override int RecordsAffected => 0; + public override int RecordsAffected => _resultSets.Aggregate(0, (a, r) => a + r.Count); public override bool GetBoolean(int ordinal) => (bool)_currentRow[ordinal]; @@ -110,10 +125,7 @@ public override long GetChars(int ordinal, long dataOffset, char[] buffer, int b throw new NotImplementedException(); } - public override string GetDataTypeName(int ordinal) - { - throw new NotImplementedException(); - } + public override string GetDataTypeName(int ordinal) => GetFieldType(ordinal).Name; public override DateTime GetDateTime(int ordinal) => (DateTime)_currentRow[ordinal]; @@ -127,9 +139,9 @@ public override IEnumerator GetEnumerator() } public override Type GetFieldType(int ordinal) - { - throw new NotImplementedException(); - } + => _results.Count > 0 + ? _results[0][ordinal]?.GetType() ?? typeof(object) + : typeof(object); public override float GetFloat(int ordinal) => (float)_currentRow[ordinal]; @@ -153,7 +165,13 @@ public override int GetValues(object[] values) public override bool NextResult() { - throw new NotImplementedException(); + var hasResult = _resultSets.Count > ++_currentResultSet; + if (hasResult) + { + _results = _resultSets[_currentResultSet]; + } + + return hasResult; } } } diff --git a/test/EFCore.Specification.Tests/InterceptionTestBase.cs b/test/EFCore.Specification.Tests/InterceptionTestBase.cs index e678eed898d..941a4a69b78 100644 --- a/test/EFCore.Specification.Tests/InterceptionTestBase.cs +++ b/test/EFCore.Specification.Tests/InterceptionTestBase.cs @@ -177,7 +177,7 @@ public virtual ITestDiagnosticListener SubscribeToDiagnosticListener(DbContextId public virtual DbContextOptions CreateOptions( IEnumerable appInterceptors, IEnumerable injectedInterceptors) - => base.AddOptions( + => AddOptions( TestStore .AddProviderOptions( new DbContextOptionsBuilder() diff --git a/test/EFCore.Specification.Tests/TestUtilities/DataGenerator.cs b/test/EFCore.Specification.Tests/TestUtilities/DataGenerator.cs new file mode 100644 index 00000000000..91c12789524 --- /dev/null +++ b/test/EFCore.Specification.Tests/TestUtilities/DataGenerator.cs @@ -0,0 +1,47 @@ +// 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.Concurrent; +using System.Linq; + +namespace Microsoft.EntityFrameworkCore.TestUtilities +{ + public static class DataGenerator + { + private static readonly ConcurrentDictionary _boolCombinations + = new ConcurrentDictionary(); + + public static object[][] GetBoolCombinations(int length) + => _boolCombinations.GetOrAdd(length, l => GetCombinations(new object[] { false, true }, l)); + + public static object[][] GetCombinations(object[] set, int length) + { + var sets = new object[length][]; + Array.Fill(sets, set); + return GetCombinations(sets); + } + + public static object[][] GetCombinations(object[][] sets) + { + var numberOfCombinations = sets.Aggregate(1L, (current, set) => current * set.Length); + var combinations = new object[numberOfCombinations][]; + + for (var i = 0L; i < numberOfCombinations; i++) + { + var combination = new object[sets.Length]; + var temp = i; + for (var j = 0; j < sets.Length; j++) + { + var set = sets[j]; + combination[j] = set[(int)(temp % set.Length)]; + temp /= set.Length; + } + + combinations[i] = combination; + } + + return combinations; + } + } +} diff --git a/test/EFCore.Specification.Tests/TestUtilities/TestHelpers.cs b/test/EFCore.Specification.Tests/TestUtilities/TestHelpers.cs index dd02d3347f3..db8b0b2482f 100644 --- a/test/EFCore.Specification.Tests/TestUtilities/TestHelpers.cs +++ b/test/EFCore.Specification.Tests/TestUtilities/TestHelpers.cs @@ -75,7 +75,7 @@ public void TestDependenciesClone(params string[] ignorePropertie } else { - Assert.Same(property.GetValue(clone), property.GetValue(dependencies)); + Assert.Equal(property.GetValue(clone), property.GetValue(dependencies)); } } } diff --git a/test/EFCore.SqlServer.FunctionalTests/CommandInterceptionSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/CommandInterceptionSqlServerTest.cs index c84c66240d0..6a5a347c193 100644 --- a/test/EFCore.SqlServer.FunctionalTests/CommandInterceptionSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/CommandInterceptionSqlServerTest.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal; using Microsoft.EntityFrameworkCore.TestUtilities; using Microsoft.Extensions.DependencyInjection; using Xunit; @@ -66,6 +68,13 @@ public CommandInterceptionSqlServerTest(InterceptionSqlServerFixture fixture) public class InterceptionSqlServerFixture : InterceptionSqlServerFixtureBase { protected override bool ShouldSubscribeToDiagnosticListener => false; + + public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) + { + new SqlServerDbContextOptionsBuilder(base.AddOptions(builder)) + .ExecutionStrategy(d => new SqlServerExecutionStrategy(d)); + return builder; + } } } @@ -81,6 +90,13 @@ public CommandInterceptionWithDiagnosticsSqlServerTest(InterceptionSqlServerFixt public class InterceptionSqlServerFixture : InterceptionSqlServerFixtureBase { protected override bool ShouldSubscribeToDiagnosticListener => true; + + public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) + { + new SqlServerDbContextOptionsBuilder(base.AddOptions(builder)) + .ExecutionStrategy(d => new SqlServerExecutionStrategy(d)); + return builder; + } } } } diff --git a/test/EFCore.SqlServer.FunctionalTests/ExecutionStrategyTest.cs b/test/EFCore.SqlServer.FunctionalTests/ExecutionStrategyTest.cs index 772d4caa7ea..55ef0ee8b5b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/ExecutionStrategyTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/ExecutionStrategyTest.cs @@ -2,6 +2,7 @@ // 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.Data; using System.Linq; using System.Threading; @@ -31,65 +32,56 @@ public ExecutionStrategyTest(ExecutionStrategyFixture fixture) protected ExecutionStrategyFixture Fixture { get; } - [ConditionalFact] - public void Does_not_throw_or_retry_on_false_commit_failure() - { - Test_commit_failure(false); - } - - [ConditionalFact] - public void Retries_on_true_commit_failure() - { - Test_commit_failure(true); - } - - private void Test_commit_failure(bool realFailure) + [ConditionalTheory] + [MemberData(nameof(DataGenerator.GetBoolCombinations), 1, MemberType = typeof(DataGenerator))] + public void Handles_commit_failure(bool realFailure) { + // Use all overloads of ExecuteInTransaction Test_commit_failure( realFailure, (e, db) => e.ExecuteInTransaction( - () => db.SaveChanges(acceptAllChangesOnSuccess: false), + () => { db.SaveChanges(false); }, () => db.Products.AsNoTracking().Any())); Test_commit_failure( realFailure, (e, db) => e.ExecuteInTransaction( - () => db.SaveChanges(acceptAllChangesOnSuccess: false), + () => db.SaveChanges(false), () => db.Products.AsNoTracking().Any())); Test_commit_failure( realFailure, (e, db) => e.ExecuteInTransaction( db, - c => c.SaveChanges(acceptAllChangesOnSuccess: false), + c => { c.SaveChanges(false); }, c => c.Products.AsNoTracking().Any())); Test_commit_failure( realFailure, (e, db) => e.ExecuteInTransaction( db, - c => c.SaveChanges(acceptAllChangesOnSuccess: false), + c => c.SaveChanges(false), c => c.Products.AsNoTracking().Any())); Test_commit_failure( realFailure, (e, db) => e.ExecuteInTransaction( - () => db.SaveChanges(acceptAllChangesOnSuccess: false), + () => { db.SaveChanges(false); }, () => db.Products.AsNoTracking().Any(), IsolationLevel.Serializable)); Test_commit_failure( realFailure, (e, db) => e.ExecuteInTransaction( - () => db.SaveChanges(acceptAllChangesOnSuccess: false), + () => db.SaveChanges(false), () => db.Products.AsNoTracking().Any(), IsolationLevel.Serializable)); Test_commit_failure( realFailure, (e, db) => e.ExecuteInTransaction( db, - c => c.SaveChanges(acceptAllChangesOnSuccess: false), + c => { c.SaveChanges(false); }, c => c.Products.AsNoTracking().Any(), IsolationLevel.Serializable)); Test_commit_failure( realFailure, (e, db) => e.ExecuteInTransaction( db, - c => c.SaveChanges(acceptAllChangesOnSuccess: false), + c => c.SaveChanges(false), c => c.Products.AsNoTracking().Any(), IsolationLevel.Serializable)); } @@ -133,87 +125,77 @@ private void Test_commit_failure(bool realFailure, Action e.ExecuteInTransactionAsync( - () => db.SaveChangesAsync(acceptAllChangesOnSuccess: false), + () => db.SaveChangesAsync(false), () => db.Products.AsNoTracking().AnyAsync())); - var cancellationToken = CancellationToken.None; await Test_commit_failure_async( realFailure, (e, db) => e.ExecuteInTransactionAsync( - async ct => await db.SaveChangesAsync(acceptAllChangesOnSuccess: false), + async ct => { await db.SaveChangesAsync(false); }, ct => db.Products.AsNoTracking().AnyAsync(), - cancellationToken)); + CancellationToken.None)); await Test_commit_failure_async( realFailure, (e, db) => e.ExecuteInTransactionAsync( - ct => db.SaveChangesAsync(acceptAllChangesOnSuccess: false), + ct => db.SaveChangesAsync(false, ct), ct => db.Products.AsNoTracking().AnyAsync(), - cancellationToken)); + CancellationToken.None)); await Test_commit_failure_async( realFailure, (e, db) => e.ExecuteInTransactionAsync( db, - async (c, ct) => await c.SaveChangesAsync(acceptAllChangesOnSuccess: false), + async (c, ct) => { await c.SaveChangesAsync(false, ct); }, (c, ct) => c.Products.AsNoTracking().AnyAsync(), - cancellationToken)); + CancellationToken.None)); await Test_commit_failure_async( realFailure, (e, db) => e.ExecuteInTransactionAsync( db, - (c, ct) => c.SaveChangesAsync(acceptAllChangesOnSuccess: false), + (c, ct) => c.SaveChangesAsync(false, ct), (c, ct) => c.Products.AsNoTracking().AnyAsync(), - cancellationToken)); + CancellationToken.None)); await Test_commit_failure_async( realFailure, (e, db) => e.ExecuteInTransactionAsync( - () => db.SaveChangesAsync(acceptAllChangesOnSuccess: false), + () => db.SaveChangesAsync(false), () => db.Products.AsNoTracking().AnyAsync(), IsolationLevel.Serializable)); await Test_commit_failure_async( realFailure, (e, db) => e.ExecuteInTransactionAsync( - async ct => await db.SaveChangesAsync(acceptAllChangesOnSuccess: false), - ct => db.Products.AsNoTracking().AnyAsync(), + async ct => { await db.SaveChangesAsync(false, ct); }, + ct => db.Products.AsNoTracking().AnyAsync(ct), IsolationLevel.Serializable, - cancellationToken)); + CancellationToken.None)); await Test_commit_failure_async( realFailure, (e, db) => e.ExecuteInTransactionAsync( - ct => db.SaveChangesAsync(acceptAllChangesOnSuccess: false), - ct => db.Products.AsNoTracking().AnyAsync(), + ct => db.SaveChangesAsync(false, ct), + ct => db.Products.AsNoTracking().AnyAsync(ct), IsolationLevel.Serializable, - cancellationToken)); + CancellationToken.None)); await Test_commit_failure_async( realFailure, (e, db) => e.ExecuteInTransactionAsync( db, - async (c, ct) => await c.SaveChangesAsync(acceptAllChangesOnSuccess: false), - (c, ct) => c.Products.AsNoTracking().AnyAsync(), + async (c, ct) => { await c.SaveChangesAsync(false, ct); }, + (c, ct) => c.Products.AsNoTracking().AnyAsync(ct), IsolationLevel.Serializable, - cancellationToken)); + CancellationToken.None)); await Test_commit_failure_async( realFailure, (e, db) => e.ExecuteInTransactionAsync( db, - (c, ct) => c.SaveChangesAsync(acceptAllChangesOnSuccess: false), - (c, ct) => c.Products.AsNoTracking().AnyAsync(), + (c, ct) => c.SaveChangesAsync(false, ct), + (c, ct) => c.Products.AsNoTracking().AnyAsync(ct), IsolationLevel.Serializable, - cancellationToken)); + CancellationToken.None)); } private async Task Test_commit_failure_async( @@ -226,11 +208,27 @@ private async Task Test_commit_failure_async( var connection = (TestSqlServerConnection)context.GetService(); connection.CommitFailures.Enqueue(new bool?[] { realFailure }); + Fixture.TestSqlLoggerFactory.Clear(); context.Products.Add(new Product()); await execute(new TestSqlServerRetryingExecutionStrategy(context), context); context.ChangeTracker.AcceptAllChanges(); + var retryMessage = + "A transient exception has been encountered during execution and the operation will be retried after 0ms." + + Environment.NewLine + + "Microsoft.Data.SqlClient.SqlException (0x80131904): Bang!"; + if (realFailure) + { + var logEntry = Fixture.TestSqlLoggerFactory.Log.Single(l => l.Id == CoreEventId.ExecutionStrategyRetrying); + Assert.Contains(retryMessage, logEntry.Message); + Assert.Equal(LogLevel.Information, logEntry.Level); + } + else + { + Assert.Empty(Fixture.TestSqlLoggerFactory.Log.Where(l => l.Id == CoreEventId.ExecutionStrategyRetrying)); + } + Assert.Equal(realFailure ? 3 : 2, connection.OpenCount); } @@ -240,19 +238,9 @@ private async Task Test_commit_failure_async( } } - [ConditionalFact] - public void Does_not_throw_or_retry_on_false_commit_failure_multiple_SaveChanges() - { - Test_commit_failure_multiple_SaveChanges(false); - } - - [ConditionalFact] - public void Retries_on_true_commit_failure_multiple_SaveChanges() - { - Test_commit_failure_multiple_SaveChanges(true); - } - - private void Test_commit_failure_multiple_SaveChanges(bool realFailure) + [ConditionalTheory] + [MemberData(nameof(DataGenerator.GetBoolCombinations), 1, MemberType = typeof(DataGenerator))] + public void Handles_commit_failure_multiple_SaveChanges(bool realFailure) { CleanContext(); @@ -274,9 +262,9 @@ private void Test_commit_failure_multiple_SaveChanges(bool realFailure) context2.Database.UseTransaction(null); context2.Database.UseTransaction(context1.Database.CurrentTransaction.GetDbTransaction()); - c1.SaveChanges(acceptAllChangesOnSuccess: false); + c1.SaveChanges(false); - return context2.SaveChanges(acceptAllChangesOnSuccess: false); + return context2.SaveChanges(false); }, c => c.Products.AsNoTracking().Any()); @@ -292,15 +280,9 @@ private void Test_commit_failure_multiple_SaveChanges(bool realFailure) } [ConditionalTheory] - [InlineData(false, false, false)] - [InlineData(true, false, false)] - [InlineData(false, true, false)] - [InlineData(true, true, false)] - [InlineData(false, false, true)] - [InlineData(true, false, true)] - [InlineData(false, true, true)] - [InlineData(true, true, true)] - public async Task Retries_only_on_true_execution_failure(bool realFailure, bool openConnection, bool async) + [MemberData(nameof(DataGenerator.GetBoolCombinations), 4, MemberType = typeof(DataGenerator))] + public async Task Retries_SaveChanges_on_execution_failure( + bool realFailure, bool externalStrategy, bool openConnection, bool async) { CleanContext(); @@ -331,31 +313,45 @@ public async Task Retries_only_on_true_execution_failure(bool realFailure, bool if (async) { - await new TestSqlServerRetryingExecutionStrategy(context).ExecuteInTransactionAsync( - context, - (c, _) => c.SaveChangesAsync(acceptAllChangesOnSuccess: false), - (c, _) => - { - // This shouldn't be called if SaveChanges failed - Assert.True(false); - return Task.FromResult(false); - }); + if (externalStrategy) + { + await new TestSqlServerRetryingExecutionStrategy(context).ExecuteInTransactionAsync( + context, + (c, ct) => c.SaveChangesAsync(false, ct), + (c, _) => + { + Assert.True(false); + return Task.FromResult(false); + }); + + context.ChangeTracker.AcceptAllChanges(); + } + else + { + await context.SaveChangesAsync(); + } } else { - new TestSqlServerRetryingExecutionStrategy(context).ExecuteInTransaction( - context, - c => c.SaveChanges(acceptAllChangesOnSuccess: false), - c => - { - // This shouldn't be called if SaveChanges failed - Assert.True(false); - return false; - }); + if (externalStrategy) + { + new TestSqlServerRetryingExecutionStrategy(context).ExecuteInTransaction( + context, + c => c.SaveChanges(false), + c => + { + Assert.True(false); + return false; + }); + + context.ChangeTracker.AcceptAllChanges(); + } + else + { + context.SaveChanges(); + } } - context.ChangeTracker.AcceptAllChanges(); - Assert.Equal(2, connection.OpenCount); Assert.Equal(4, connection.ExecutionCount); @@ -386,9 +382,8 @@ public async Task Retries_only_on_true_execution_failure(bool realFailure, bool } [ConditionalTheory] - [InlineData(false)] - //[InlineData(true)] - public async Task Retries_query_on_execution_failure(bool async) + [MemberData(nameof(DataGenerator.GetBoolCombinations), 2, MemberType = typeof(DataGenerator))] + public async Task Retries_query_on_execution_failure(bool externalStrategy, bool async) { CleanContext(); @@ -408,36 +403,100 @@ public async Task Retries_query_on_execution_failure(bool async) Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State); + List list; if (async) { - var list = await new TestSqlServerRetryingExecutionStrategy(context).ExecuteInTransactionAsync( - context, - (c, _) => context.Products.ToListAsync(), - (c, _) => - { - // This shouldn't be called if query failed - Assert.True(false); - return Task.FromResult(false); - }); - - Assert.Equal(2, list.Count); + if (externalStrategy) + { + list = await new TestSqlServerRetryingExecutionStrategy(context) + .ExecuteAsync(context, (c, ct) => c.Products.ToListAsync(ct), null); + } + else + { + list = await context.Products.ToListAsync(); + } } else { - var list = new TestSqlServerRetryingExecutionStrategy(context).ExecuteInTransaction( - context, - c => context.Products.ToList(), - c => - { - // This shouldn't be called if query failed - Assert.True(false); - return false; - }); + if (externalStrategy) + { + list = new TestSqlServerRetryingExecutionStrategy(context) + .Execute(context, c => c.Products.ToList(), null); + } + else + { + list = context.Products.ToList(); + } + } + + Assert.Equal(2, list.Count); + Assert.Equal(1, connection.OpenCount); + Assert.Equal(2, connection.ExecutionCount); + + Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State); + } + } + + [ConditionalTheory] + [MemberData(nameof(DataGenerator.GetBoolCombinations), 2, MemberType = typeof(DataGenerator))] + public async Task Retries_FromSqlRaw_on_execution_failure(bool externalStrategy, bool async) + { + CleanContext(); + + using (var context = CreateContext()) + { + context.Products.Add(new Product()); + context.Products.Add(new Product()); + + context.SaveChanges(); + } + + using (var context = CreateContext()) + { + var connection = (TestSqlServerConnection)context.GetService(); + + connection.ExecutionFailures.Enqueue(new bool?[] { true }); + + Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State); - Assert.Equal(2, list.Count); + List list; + if (async) + { + if (externalStrategy) + { + list = await new TestSqlServerRetryingExecutionStrategy(context) + .ExecuteAsync( + context, (c, ct) => c.Set().FromSqlRaw( + @"SELECT [ID], [name] + FROM [Products]").ToListAsync(ct), null); + } + else + { + list = await context.Set().FromSqlRaw( + @"SELECT [ID], [name] + FROM [Products]").ToListAsync(); + } + } + else + { + if (externalStrategy) + { + list = new TestSqlServerRetryingExecutionStrategy(context) + .Execute( + context, c => c.Set().FromSqlRaw( + @"SELECT [ID], [name] + FROM [Products]").ToList(), null); + } + else + { + list = context.Set().FromSqlRaw( + @"SELECT [ID], [name] + FROM [Products]").ToList(); + } } - Assert.Equal(2, connection.OpenCount); + Assert.Equal(2, list.Count); + Assert.Equal(1, connection.OpenCount); Assert.Equal(2, connection.ExecutionCount); Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State); @@ -445,9 +504,8 @@ public async Task Retries_query_on_execution_failure(bool async) } [ConditionalTheory] - [InlineData(false)] - [InlineData(true)] - public async Task Retries_OpenConnection_on_execution_failure(bool async) + [MemberData(nameof(DataGenerator.GetBoolCombinations), 2, MemberType = typeof(DataGenerator))] + public async Task Retries_OpenConnection_on_execution_failure(bool externalStrategy, bool async) { using (var context = CreateContext()) { @@ -459,15 +517,29 @@ public async Task Retries_OpenConnection_on_execution_failure(bool async) if (async) { - await new TestSqlServerRetryingExecutionStrategy(context).ExecuteAsync( - context, - c => context.Database.OpenConnectionAsync()); + if (externalStrategy) + { + await new TestSqlServerRetryingExecutionStrategy(context).ExecuteAsync( + context, + c => c.Database.OpenConnectionAsync()); + } + else + { + await context.Database.OpenConnectionAsync(); + } } else { - new TestSqlServerRetryingExecutionStrategy(context).Execute( - context, - c => context.Database.OpenConnection()); + if (externalStrategy) + { + new TestSqlServerRetryingExecutionStrategy(context).Execute( + context, + c => c.Database.OpenConnection()); + } + else + { + context.Database.OpenConnection(); + } } Assert.Equal(2, connection.OpenCount); @@ -539,7 +611,7 @@ public void Verification_is_retried_using_same_retry_limit() new TestSqlServerRetryingExecutionStrategy(context, TimeSpan.FromMilliseconds(100)) .ExecuteInTransaction( context, - c => c.SaveChanges(acceptAllChangesOnSuccess: false), + c => c.SaveChanges(false), c => false)); context.ChangeTracker.AcceptAllChanges(); @@ -594,12 +666,10 @@ public class ExecutionStrategyFixture : SharedStoreFixtureBase protected override Type ContextType { get; } = typeof(ExecutionStrategyContext); protected override IServiceCollection AddServices(IServiceCollection serviceCollection) - { - return base.AddServices(serviceCollection) + => base.AddServices(serviceCollection) .AddSingleton() .AddScoped() .AddSingleton(); - } public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) { diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs index 6be9d5d268d..d7566603f4e 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs @@ -124,22 +124,10 @@ public async Task Concurrent_async_queries_when_raw_query() { while (await asyncEnumerator.MoveNextAsync()) { - if (!context.GetService().IsMultipleActiveResultSetsEnabled) - { - // Not supported, we could make it work by triggering buffering - // from RelationalCommand. - - await Assert.ThrowsAsync( - () => context.Database.ExecuteSqlRawAsync( - "[dbo].[CustOrderHist] @CustomerID = {0}", - asyncEnumerator.Current.CustomerID)); - } - else - { - await context.Database.ExecuteSqlRawAsync( - "[dbo].[CustOrderHist] @CustomerID = {0}", - asyncEnumerator.Current.CustomerID); - } + // Outer query is buffered by default + await context.Database.ExecuteSqlRawAsync( + "[dbo].[CustOrderHist] @CustomerID = {0}", + asyncEnumerator.Current.CustomerID); } } } diff --git a/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestSqlServerRetryingExecutionStrategy.cs b/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestSqlServerRetryingExecutionStrategy.cs index c1b1477a3ee..9ee9e32f08f 100644 --- a/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestSqlServerRetryingExecutionStrategy.cs +++ b/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestSqlServerRetryingExecutionStrategy.cs @@ -66,9 +66,7 @@ protected override bool ShouldRetryOn(Exception exception) } return exception is InvalidOperationException invalidOperationException - && invalidOperationException.Message == "Internal .Net Framework Data Provider error 6." - ? true - : false; + && invalidOperationException.Message == "Internal .Net Framework Data Provider error 6."; } public new virtual TimeSpan? GetNextDelay(Exception lastException) diff --git a/test/EFCore.SqlServer.Tests/Storage/SqlServerRetryingExecutionStrategyTests.cs b/test/EFCore.SqlServer.Tests/Storage/SqlServerRetryingExecutionStrategyTests.cs index 195eeb26d8d..e6b4dbd267b 100644 --- a/test/EFCore.SqlServer.Tests/Storage/SqlServerRetryingExecutionStrategyTests.cs +++ b/test/EFCore.SqlServer.Tests/Storage/SqlServerRetryingExecutionStrategyTests.cs @@ -6,6 +6,7 @@ using Microsoft.EntityFrameworkCore.TestUtilities; using Xunit; +// ReSharper disable InconsistentNaming namespace Microsoft.EntityFrameworkCore.Storage { public class SqlServerRetryingExecutionStrategyTests @@ -14,13 +15,13 @@ public class SqlServerRetryingExecutionStrategyTests public void GetNextDelay_returns_shorter_delay_for_InMemory_transient_errors() { var strategy = new TestSqlServerRetryingExecutionStrategy(CreateContext()); - var inMemoryOltpError = SqlExceptionFactory.CreateSqlException(41302); + var inMemoryError = SqlExceptionFactory.CreateSqlException(41302); var delays = new List(); - var delay = strategy.GetNextDelay(inMemoryOltpError); + var delay = strategy.GetNextDelay(inMemoryError); while (delay != null) { delays.Add(delay.Value); - delay = strategy.GetNextDelay(inMemoryOltpError); + delay = strategy.GetNextDelay(inMemoryError); } var expectedDelays = new List @@ -39,7 +40,7 @@ public void GetNextDelay_returns_shorter_delay_for_InMemory_transient_errors() Assert.True( Math.Abs((delays[i] - expectedDelays[i]).TotalMilliseconds) <= expectedDelays[i].TotalMilliseconds * 0.1 + 1, - string.Format("Expected: {0}; Actual: {1}", expectedDelays[i], delays[i])); + $"Expected: {expectedDelays[i]}; Actual: {delays[i]}"); } } diff --git a/test/EFCore.Tests/Query/CompiledQueryCacheKeyGeneratorDependenciesTest.cs b/test/EFCore.Tests/Query/CompiledQueryCacheKeyGeneratorDependenciesTest.cs index 2a764195436..ddd60403e24 100644 --- a/test/EFCore.Tests/Query/CompiledQueryCacheKeyGeneratorDependenciesTest.cs +++ b/test/EFCore.Tests/Query/CompiledQueryCacheKeyGeneratorDependenciesTest.cs @@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore.TestUtilities; using Xunit; +// ReSharper disable InconsistentNaming namespace Microsoft.EntityFrameworkCore.Query { public class CompiledQueryCacheKeyGeneratorDependenciesTest diff --git a/test/EFCore.Tests/Query/QueryCompilationContextDependenciesTest.cs b/test/EFCore.Tests/Query/QueryCompilationContextDependenciesTest.cs index 0f54c5a15f1..83cfe5c25ca 100644 --- a/test/EFCore.Tests/Query/QueryCompilationContextDependenciesTest.cs +++ b/test/EFCore.Tests/Query/QueryCompilationContextDependenciesTest.cs @@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore.TestUtilities; using Xunit; +// ReSharper disable InconsistentNaming namespace Microsoft.EntityFrameworkCore.Query { public class QueryCompilationContextDependenciesTest diff --git a/test/EFCore.Tests/Storage/ExecutionStrategyTest.cs b/test/EFCore.Tests/Storage/ExecutionStrategyTest.cs index 6cd9632e233..718d2d68fc5 100644 --- a/test/EFCore.Tests/Storage/ExecutionStrategyTest.cs +++ b/test/EFCore.Tests/Storage/ExecutionStrategyTest.cs @@ -65,7 +65,7 @@ public void GetNextDelay_returns_the_expected_default_sequence() Assert.True( Math.Abs((delays[i] - expectedDelays[i]).TotalMilliseconds) <= expectedDelays[i].TotalMilliseconds * 0.1 + 1, - string.Format("Expected: {0}; Actual: {1}", expectedDelays[i], delays[i])); + $"Expected: {expectedDelays[i]}; Actual: {delays[i]}"); } } @@ -281,18 +281,18 @@ private void Execute_retries_until_successful(Action e.Execute(() => f())); + Execute_retries_until_not_retriable_exception_is_thrown((e, f) => e.Execute(() => f())); } [ConditionalFact] - public void Execute_Func_retries_until_not_retrieable_exception_is_thrown() + public void Execute_Func_retries_until_not_retriable_exception_is_thrown() { - Execute_retries_until_not_retrieable_exception_is_thrown((e, f) => e.Execute(f)); + Execute_retries_until_not_retriable_exception_is_thrown((e, f) => e.Execute(f)); } - private void Execute_retries_until_not_retrieable_exception_is_thrown(Action> execute) + private void Execute_retries_until_not_retriable_exception_is_thrown(Action> execute) { var executionStrategyMock = new TestExecutionStrategy( Context,