diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosSqlTranslatingExpressionVisitor.cs b/src/EFCore.Cosmos/Query/Internal/CosmosSqlTranslatingExpressionVisitor.cs index 94637bf4aad..0d1cc9bf911 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosSqlTranslatingExpressionVisitor.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosSqlTranslatingExpressionVisitor.cs @@ -225,11 +225,18 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression) if (binaryExpression.NodeType == ExpressionType.Coalesce) { + var ifTrue = binaryExpression.Left; + var ifFalse = binaryExpression.Right; + if (ifTrue.Type != ifFalse.Type) + { + ifFalse = Expression.Convert(ifFalse, ifTrue.Type); + } + return Visit( Expression.Condition( - Expression.NotEqual(binaryExpression.Left, Expression.Constant(null, binaryExpression.Left.Type)), - binaryExpression.Left, - binaryExpression.Right)); + Expression.NotEqual(ifTrue, Expression.Constant(null, ifTrue.Type)), + ifTrue, + ifFalse)); } var left = TryRemoveImplicitConvert(binaryExpression.Left); diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs index 9e77b740c3b..ba8801cb58a 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs @@ -1455,6 +1455,12 @@ FROM root c WHERE ((c[""Discriminator""] = ""Customer"") AND (c[""CustomerID""] = ""ALFKI""))"); } + [ConditionalTheory(Skip = "Issue #17246")] + public override Task SelectMany_Joined_DefaultIfEmpty3(bool async) + { + return base.SelectMany_Joined_DefaultIfEmpty3(async); + } + [ConditionalTheory(Skip = "Issue #17246")] public override async Task SelectMany_Joined(bool async) { diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs index c92c2e8a4c8..a5f49f56f71 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs @@ -882,6 +882,7 @@ FROM root c WHERE (c[""Discriminator""] = ""Order"")"); } + [ConditionalTheory(Skip = "Issue#17246")] public override async Task Select_GetValueOrDefault_on_DateTime_with_null_values(bool async) { await base.Select_GetValueOrDefault_on_DateTime_with_null_values(async); @@ -1039,6 +1040,22 @@ public override Task Collection_projection_AsNoTracking_OrderBy(bool async) return base.Collection_projection_AsNoTracking_OrderBy(async); } + public override async Task Coalesce_over_nullable_uint(bool async) + { + await base.Coalesce_over_nullable_uint(async); + + AssertSql( + @"SELECT ((c[""EmployeeID""] != null) ? c[""EmployeeID""] : 0) AS c +FROM root c +WHERE (c[""Discriminator""] = ""Order"")"); + } + + [ConditionalTheory(Skip = "Issue#17246")] + public override Task Project_uint_through_collection_FirstOrDefault(bool async) + { + return base.Project_uint_through_collection_FirstOrDefault(async); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs index 3020bd67816..3ceb09986f9 100644 --- a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs @@ -1138,6 +1138,17 @@ public virtual Task Select_null_propagation_negative8(bool async) : null)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_null_propagation_negative9(bool async) + { + return AssertQueryScalar( + async, + ss => ss.Set().Select(g => g.LeaderNickname != null + ? (bool?)(g.Nickname.Length == 5) ?? default(bool) + : (bool?)null)); + } + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Select_null_propagation_works_for_navigations_with_composite_keys(bool async) diff --git a/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs index 45a544a2ac0..789b7dae0fb 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs @@ -2916,6 +2916,19 @@ from o in ss.Set().Where(o => o.CustomerID == c.CustomerID).DefaultIfEmpt entryCount: 830); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task SelectMany_Joined_DefaultIfEmpty3(bool async) + { + return AssertQuery( + async, + ss => + from c in ss.Set() + from o in ss.Set().Where(o => o.CustomerID == c.CustomerID).Where(o => o.OrderDetails.Any()).DefaultIfEmpty() + select o, + entryCount: 830); + } + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Select_many_cross_join_same_collection(bool async) diff --git a/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs index 4fd8e829969..41b3672847d 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs @@ -1169,7 +1169,7 @@ public virtual Task Select_GetValueOrDefault_on_DateTime(bool async) ss => ss.Set().Select(o => o.OrderDate.GetValueOrDefault())); } - [ConditionalTheory(Skip = "issue #13004")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Select_GetValueOrDefault_on_DateTime_with_null_values(bool async) { @@ -1615,5 +1615,25 @@ public virtual Task Collection_projection_AsNoTracking_OrderBy(bool async) AssertCollection(e.Orders, a.Orders, elementSorter: i => i, elementAsserter: (ie, ia) => Assert.Equal(ie, ia)); }); } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Coalesce_over_nullable_uint(bool async) + { + return AssertQueryScalar( + async, + ss => ss.Set().Select(o => o.EmployeeID ?? 0)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Project_uint_through_collection_FirstOrDefault(bool async) + { + return AssertQueryScalar( + async, + ss => ss.Set().Select(c => c.Orders.OrderBy(o => o.OrderID).FirstOrDefault()).Select(e => e.EmployeeID), + ss => ss.Set().Select(c => c.Orders.OrderBy(o => o.OrderID).FirstOrDefault()) + .Select(e => MaybeScalar(e, () => e.EmployeeID))); + } } } diff --git a/test/EFCore.Specification.Tests/TestUtilities/QueryTestGeneration/ProceduralQueryExpressionGenerator.cs b/test/EFCore.Specification.Tests/TestUtilities/QueryTestGeneration/ProceduralQueryExpressionGenerator.cs index b28449a1ae2..2cf95889037 100644 --- a/test/EFCore.Specification.Tests/TestUtilities/QueryTestGeneration/ProceduralQueryExpressionGenerator.cs +++ b/test/EFCore.Specification.Tests/TestUtilities/QueryTestGeneration/ProceduralQueryExpressionGenerator.cs @@ -127,7 +127,6 @@ static ProcedurallyGeneratedQueryExecutor() AddExpectedFailure("Except_dbset", "cannot be used for"); // 12568 AddExpectedFailure("Except_nested", "cannot be used for"); // 12568 - AddExpectedFailure("GroupBy_aggregate_Pushdown", "Invalid column name 'c'."); // 12569 AddExpectedFailure("GroupBy_with_orderby_take_skip_distinct", "Invalid column name 'c'."); // 12569 AddExpectedFailure( @@ -186,21 +185,10 @@ static ProcedurallyGeneratedQueryExecutor() AddExpectedFailure("GroupBy_Shadow3", "Value does not fall within the expected range."); // 12088 AddExpectedFailure("GroupBy_SelectMany", "Value does not fall within the expected range."); // 12088 - AddExpectedFailure( - "Select_collection_navigation_simple", - "Index was out of range. Must be non-negative and less than the size of the collection."); // 12643 - AddExpectedFailure( - "Correlated_collections_nested_with_custom_ordering", - "Index was out of range. Must be non-negative and less than the size of the collection."); // 12643 - AddExpectedFailure( - "Correlated_collections_multiple_nested_complex_collections", - "Index was out of range. Must be non-negative and less than the size of the collection."); // 12643 - AddExpectedFailure("GroupJoin_GroupBy_Aggregate_5", "Incorrect syntax near '+'."); // 12656 AddExpectedFailure("GroupBy_Key_as_part_of_element_selector", "Incorrect syntax near '+'."); // 12656 AddExpectedFailure("GroupBy_Property_Select_Key_Min", "Incorrect syntax near '+'."); // 12656 AddExpectedFailure("GroupBy_Property_Include_Aggregate_with_anonymous_selector", "Incorrect syntax near '+'."); // 12656 - AddExpectedFailure("GroupBy_aggregate_Pushdown", "Incorrect syntax near '+'."); // 12656 AddExpectedFailure("GroupBy_anonymous_with_alias_Select_Key_Sum", "Incorrect syntax near '+'."); // 12656 AddExpectedFailure("GroupBy_Property_Select_Key_LongCount", "Incorrect syntax near '+'."); // 12656 AddExpectedFailure("GroupBy_filter_count_OrderBy_count_Select_sum", "Incorrect syntax near '+'."); // 12656 @@ -306,33 +294,12 @@ static ProcedurallyGeneratedQueryExecutor() AddExpectedFailure("Where_Join_Any", "Conversion failed when converting date and/or time from character string."); // 12797 AddExpectedFailure("Where_Join_Exists", "Conversion failed when converting date and/or time from character string."); // 12797 - AddExpectedFailure( - "Parameter_extraction_short_circuits_1", - "An exception was thrown while attempting to evaluate the LINQ query parameter expression"); // 12820 - AddExpectedFailure( - "Parameter_extraction_short_circuits_3", - "An exception was thrown while attempting to evaluate the LINQ query parameter expression"); // 12820 - AddExpectedFailure( "Entity_equality_local", "has already been declared. Variable names must be unique within a query batch or stored procedure."); // 12871 AddExpectedFailure( "Where_poco_closure", "has already been declared. Variable names must be unique within a query batch or stored procedure."); // 12871 - - AddExpectedFailure( - "QueryType_with_included_navs_multi_level", "Object reference not set to an instance of an object."); // 12874 - - AddExpectedFailure("Select_null_propagation_negative1", "Specified cast is not valid."); // 12958 - AddExpectedFailure("Select_null_propagation_negative2", "Specified cast is not valid."); // 12958 - AddExpectedFailure("Select_null_propagation_negative3", "Specified cast is not valid."); // 12958 - AddExpectedFailure("Select_null_propagation_negative4", "Specified cast is not valid."); // 12958 - AddExpectedFailure("Select_null_propagation_negative5", "Specified cast is not valid."); // 12958 - AddExpectedFailure("Select_null_propagation_negative6", "Specified cast is not valid."); // 12958 - AddExpectedFailure("Select_null_propagation_negative7", "Specified cast is not valid."); // 12958 - - AddExpectedFailure("DefaultIfEmpty_in_subquery", "' is not defined for type '"); // 12960 - AddExpectedFailure("SelectMany_Joined_DefaultIfEmpty2", "' is not defined for type '"); // 12960 } private static void AddExpectedFailure(string testName, string expectedException) @@ -397,13 +364,6 @@ public void Execute(IQueryable query, DbContext context, str @"Error generated for warning 'Microsoft.EntityFrameworkCore.Query.IncludeIgnoredWarning")) { } - else if (exception.Message.Contains( - @"The expected type was 'System.UInt32' but the actual value was of type 'System.Int32'") - || exception.Message.Contains( - @"The expected type was 'System.Nullable`1[System.UInt32]' but the actual value was of type 'System.Int32'.") - ) // 13753 - { - } else if (exception.Message == @"The binary operator NotEqual is not defined for the types 'Microsoft.EntityFrameworkCore.Storage.ValueBuffer' and 'Microsoft.EntityFrameworkCore.Storage.ValueBuffer'." ) // 12788 diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index 1a704e273f4..a764780636d 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -1106,6 +1106,22 @@ WHERE [g].[Discriminator] IN (N'Gear', N'Officer') LEFT JOIN [Cities] AS [c] ON [t0].[AssignedCityName] = [c].[Name]"); } + public override async Task Select_null_propagation_negative9(bool async) + { + await base.Select_null_propagation_negative9(async); + + AssertSql( + @"SELECT CASE + WHEN [g].[LeaderNickname] IS NOT NULL THEN COALESCE(CASE + 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, CAST(0 AS bit)) + ELSE NULL +END +FROM [Gears] AS [g] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); + } + public override async Task Select_null_propagation_works_for_navigations_with_composite_keys(bool async) { await base.Select_null_propagation_works_for_navigations_with_composite_keys(async); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs index 6d84f6276b4..601eebe2aca 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs @@ -1859,6 +1859,23 @@ FROM [Customers] AS [c] LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID]"); } + public override async Task SelectMany_Joined_DefaultIfEmpty3(bool async) + { + await base.SelectMany_Joined_DefaultIfEmpty3(async); + + AssertSql( + @"SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate] +FROM [Customers] AS [c] +LEFT JOIN ( + SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] + FROM [Orders] AS [o] + WHERE EXISTS ( + SELECT 1 + FROM [Order Details] AS [o0] + WHERE [o].[OrderID] = [o0].[OrderID]) +) AS [t] ON [c].[CustomerID] = [t].[CustomerID]"); + } + public override async Task SelectMany_Joined_Take(bool async) { await base.SelectMany_Joined_Take(async); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs index 4e46d6c03c2..535109191e3 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs @@ -956,7 +956,7 @@ public override async Task Select_GetValueOrDefault_on_DateTime_with_null_values await base.Select_GetValueOrDefault_on_DateTime_with_null_values(async); AssertSql( - @"SELECT COALESCE([o].[OrderDate], '1753-01-01T00:00:00.000') + @"SELECT [o].[OrderDate] FROM [Customers] AS [c] LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID]"); } @@ -1303,6 +1303,28 @@ FROM [Customers] AS [c] ORDER BY [c].[CustomerID], [o].[OrderID]"); } + public override async Task Coalesce_over_nullable_uint(bool async) + { + await base.Coalesce_over_nullable_uint(async); + + AssertSql( + @"SELECT COALESCE([o].[EmployeeID], 0) +FROM [Orders] AS [o]"); + } + + public override async Task Project_uint_through_collection_FirstOrDefault(bool async) + { + await base.Project_uint_through_collection_FirstOrDefault(async); + + AssertSql( + @"SELECT ( + SELECT TOP(1) [o].[EmployeeID] + FROM [Orders] AS [o] + WHERE [c].[CustomerID] = [o].[CustomerID] + ORDER BY [o].[OrderID]) +FROM [Customers] AS [c]"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected);