Skip to content

Commit

Permalink
Ignore convert nodes from nullable to non-nullable
Browse files Browse the repository at this point in the history
Take 2 of 38c79bf

Fixes #16653
  • Loading branch information
roji committed Jul 25, 2019
1 parent e2318e8 commit 17418aa
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ protected override Expression VisitUnary(UnaryExpression unaryExpression)
// Object convert needs to be converted to explicit cast when mismatching types
if (operand.Type.IsInterface
&& unaryExpression.Type.GetInterfaces().Any(e => e == operand.Type)
|| unaryExpression.Type.UnwrapNullableType() == operand.Type
|| unaryExpression.Type.UnwrapNullableType() == operand.Type.UnwrapNullableType()
|| unaryExpression.Type.UnwrapNullableType() == typeof(Enum))
{
return sqlOperand;
Expand Down
9 changes: 9 additions & 0 deletions test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5986,5 +5986,14 @@ public virtual Task Inner_parameter_in_nested_lambdas_gets_preserved(bool isAsyn
cs => cs.Where(c => c.Orders.Where(o => c == new Customer { CustomerID = o.CustomerID }).Count() > 0),
entryCount: 89);
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Convert_to_nullable_on_nullable_value_is_ignored(bool isAsync)
{
return AssertQuery<Order>(
isAsync,
os => os.Select(o => new Order { OrderDate = o.OrderDate.Value }));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ public override async Task Where_bitwise_and_nullable_enum_with_constant(bool is
AssertSql(
@"SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId]
FROM [Weapons] AS [w]
WHERE CAST(([w].[AmmunitionType] & 1) AS int) > 0");
WHERE ([w].[AmmunitionType] & 1) > 0");
}

public override async Task Where_bitwise_and_nullable_enum_with_null_constant(bool isAsync)
Expand All @@ -570,7 +570,7 @@ public override async Task Where_bitwise_and_nullable_enum_with_null_constant(bo
AssertSql(
@"SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId]
FROM [Weapons] AS [w]
WHERE CAST(([w].[AmmunitionType] & NULL) AS int) > 0");
WHERE ([w].[AmmunitionType] & NULL) > 0");
}

public override async Task Where_bitwise_and_nullable_enum_with_non_nullable_parameter(bool isAsync)
Expand All @@ -582,7 +582,7 @@ public override async Task Where_bitwise_and_nullable_enum_with_non_nullable_par
SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId]
FROM [Weapons] AS [w]
WHERE CAST(([w].[AmmunitionType] & @__ammunitionType_0) AS int) > 0");
WHERE ([w].[AmmunitionType] & @__ammunitionType_0) > 0");
}

public override async Task Where_bitwise_and_nullable_enum_with_nullable_parameter(bool isAsync)
Expand All @@ -594,13 +594,13 @@ public override async Task Where_bitwise_and_nullable_enum_with_nullable_paramet
SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId]
FROM [Weapons] AS [w]
WHERE CAST(([w].[AmmunitionType] & @__ammunitionType_0) AS int) > 0",
WHERE ([w].[AmmunitionType] & @__ammunitionType_0) > 0",
//
@"@__ammunitionType_0='' (DbType = Int32)
SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId]
FROM [Weapons] AS [w]
WHERE CAST(([w].[AmmunitionType] & @__ammunitionType_0) AS int) > 0");
WHERE ([w].[AmmunitionType] & @__ammunitionType_0) > 0");
}

public override async Task Where_bitwise_or_enum(bool isAsync)
Expand Down Expand Up @@ -2548,14 +2548,13 @@ LEFT JOIN (
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 CAST([t0].[HasSoulPatch] AS bit) = CAST(1 AS bit)");
WHERE [t0].[HasSoulPatch] = CAST(1 AS bit)");
}

public override async Task Optional_navigation_type_compensation_works_with_predicate_negated(bool isAsync)
{
await base.Optional_navigation_type_compensation_works_with_predicate_negated(isAsync);


AssertSql(
@"SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[Note]
FROM [Tags] AS [t]
Expand All @@ -2564,7 +2563,7 @@ LEFT JOIN (
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 CAST([t0].[HasSoulPatch] AS bit) <> CAST(1 AS bit)");
WHERE [t0].[HasSoulPatch] <> CAST(1 AS bit)");
}

public override async Task Optional_navigation_type_compensation_works_with_predicate_negated_complex1(bool isAsync)
Expand Down Expand Up @@ -2596,7 +2595,7 @@ 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 CASE
WHEN CAST([t0].[HasSoulPatch] AS bit) = CAST(1 AS bit) THEN CAST(1 AS bit)
WHEN [t0].[HasSoulPatch] = CAST(1 AS bit) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END = CAST(1 AS bit)");
}
Expand Down Expand Up @@ -2638,7 +2637,7 @@ public override async Task Optional_navigation_type_compensation_works_with_proj
await base.Optional_navigation_type_compensation_works_with_projection(isAsync);

AssertSql(
@"SELECT CAST([t].[SquadId] AS int)
@"SELECT [t].[SquadId]
FROM [Tags] AS [t0]
LEFT JOIN (
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank]
Expand All @@ -2653,7 +2652,7 @@ public override async Task Optional_navigation_type_compensation_works_with_proj
await base.Optional_navigation_type_compensation_works_with_projection_into_anonymous_type(isAsync);

AssertSql(
@"SELECT CAST([t].[SquadId] AS int) AS [SquadId]
@"SELECT [t].[SquadId]
FROM [Tags] AS [t0]
LEFT JOIN (
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank]
Expand All @@ -2668,7 +2667,7 @@ public override async Task Optional_navigation_type_compensation_works_with_DTOs
await base.Optional_navigation_type_compensation_works_with_DTOs(isAsync);

AssertSql(
@"SELECT CAST([t].[SquadId] AS int) AS [Id]
@"SELECT [t].[SquadId] AS [Id]
FROM [Tags] AS [t0]
LEFT JOIN (
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank]
Expand All @@ -2683,7 +2682,7 @@ public override async Task Optional_navigation_type_compensation_works_with_list
await base.Optional_navigation_type_compensation_works_with_list_initializers(isAsync);

AssertSql(
@"SELECT CAST([t].[SquadId] AS int), [t].[SquadId] + 1
@"SELECT [t].[SquadId], [t].[SquadId] + 1
FROM [Tags] AS [t0]
LEFT JOIN (
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank]
Expand All @@ -2699,7 +2698,7 @@ public override async Task Optional_navigation_type_compensation_works_with_arra
await base.Optional_navigation_type_compensation_works_with_array_initializers(isAsync);

AssertSql(
@"SELECT CAST([t].[SquadId] AS int)
@"SELECT [t].[SquadId]
FROM [Tags] AS [t0]
LEFT JOIN (
SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank]
Expand All @@ -2722,7 +2721,7 @@ 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 ([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL
ORDER BY CAST([t0].[SquadId] AS int)");
ORDER BY [t0].[SquadId]");
}

public override async Task Optional_navigation_type_compensation_works_with_groupby(bool isAsync)
Expand Down Expand Up @@ -2755,7 +2754,7 @@ LEFT JOIN (
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 (([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL) AND (CAST([t0].[HasSoulPatch] AS bit) <> CAST(1 AS bit))) THEN CAST(1 AS bit)
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");
}
Expand All @@ -2772,7 +2771,7 @@ LEFT JOIN (
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 (([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL) AND (CAST([t0].[HasSoulPatch] AS bit) <> CAST(1 AS bit))");
WHERE (([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL) AND ([t0].[HasSoulPatch] <> CAST(1 AS bit))");
}

public override async Task Optional_navigation_type_compensation_works_with_contains(bool isAsync)
Expand All @@ -2787,7 +2786,7 @@ LEFT JOIN (
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 (([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL) AND CAST([t0].[SquadId] AS int) IN (
WHERE (([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL) AND [t0].[SquadId] IN (
SELECT [g0].[SquadId]
FROM [Gears] AS [g0]
WHERE [g0].[Discriminator] IN (N'Gear', N'Officer')
Expand Down Expand Up @@ -3261,7 +3260,7 @@ LEFT JOIN (
FROM [Gears] AS [g]
WHERE [g].[Discriminator] IN (N'Gear', N'Officer')
) AS [t] ON [w].[OwnerFullName] = [t].[FullName]
WHERE ([w].[Id] <> 50) AND (CAST([t].[HasSoulPatch] AS bit) <> CAST(1 AS bit))");
WHERE ([w].[Id] <> 50) AND ([t].[HasSoulPatch] <> CAST(1 AS bit))");
}

public override async Task Distinct_with_optional_navigation_is_translated_to_sql(bool isAsync)
Expand Down Expand Up @@ -3876,7 +3875,7 @@ public override void Navigation_access_via_EFProperty_on_derived_entity_using_ca
base.Navigation_access_via_EFProperty_on_derived_entity_using_cast();

AssertSql(
@"SELECT [f].[Name], CAST([t].[ThreatLevel] AS smallint) AS [Threat]
@"SELECT [f].[Name], [t].[ThreatLevel] AS [Threat]
FROM [Factions] AS [f]
LEFT JOIN (
SELECT [l].[Name], [l].[Discriminator], [l].[LocustHordeId], [l].[ThreatLevel], [l].[DefeatedByNickname], [l].[DefeatedBySquadId], [l].[HighCommandId]
Expand Down Expand Up @@ -4639,7 +4638,7 @@ public override async Task Projecting_nullable_bool_in_conditional_works(bool is

AssertSql(
@"SELECT CASE
WHEN [t].[Nickname] IS NOT NULL THEN CAST([t].[HasSoulPatch] AS bit)
WHEN [t].[Nickname] IS NOT NULL THEN [t].[HasSoulPatch]
ELSE CAST(0 AS bit)
END AS [Prop]
FROM [Tags] AS [t0]
Expand Down Expand Up @@ -6163,7 +6162,7 @@ public override async Task Negated_bool_ternary_inside_anonymous_type_in_project
AssertSql(
@"SELECT CASE
WHEN CASE
WHEN CAST([t].[HasSoulPatch] AS bit) = CAST(1 AS bit) THEN CAST(1 AS bit)
WHEN [t].[HasSoulPatch] = CAST(1 AS bit) THEN CAST(1 AS bit)
ELSE COALESCE([t].[HasSoulPatch], CAST(1 AS bit))
END <> CAST(1 AS bit) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ public override async Task Select_non_matching_value_types_nullable_int_to_int_d
await base.Select_non_matching_value_types_nullable_int_to_int_doesnt_introduce_explicit_cast(isAsync);

AssertSql(
@"SELECT CAST([o].[EmployeeID] AS bigint)
@"SELECT [o].[EmployeeID]
FROM [Orders] AS [o]
WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL
ORDER BY [o].[OrderID]");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3350,7 +3350,7 @@ public override async Task Select_expression_date_add_year(bool isAsync)
await base.Select_expression_date_add_year(isAsync);

AssertSql(
@"SELECT CAST(DATEADD(year, CAST(1 AS int), [o].[OrderDate]) AS datetime2) AS [OrderDate]
@"SELECT DATEADD(year, CAST(1 AS int), [o].[OrderDate]) AS [OrderDate]
FROM [Orders] AS [o]
WHERE [o].[OrderDate] IS NOT NULL");
}
Expand All @@ -3360,7 +3360,7 @@ public override async Task Select_expression_datetime_add_month(bool isAsync)
await base.Select_expression_datetime_add_month(isAsync);

AssertSql(
@"SELECT CAST(DATEADD(month, CAST(1 AS int), [o].[OrderDate]) AS datetime2) AS [OrderDate]
@"SELECT DATEADD(month, CAST(1 AS int), [o].[OrderDate]) AS [OrderDate]
FROM [Orders] AS [o]
WHERE [o].[OrderDate] IS NOT NULL");
}
Expand All @@ -3370,7 +3370,7 @@ public override async Task Select_expression_datetime_add_hour(bool isAsync)
await base.Select_expression_datetime_add_hour(isAsync);

AssertSql(
@"SELECT CAST(DATEADD(hour, CAST(1.0E0 AS int), [o].[OrderDate]) AS datetime2) AS [OrderDate]
@"SELECT DATEADD(hour, CAST(1.0E0 AS int), [o].[OrderDate]) AS [OrderDate]
FROM [Orders] AS [o]
WHERE [o].[OrderDate] IS NOT NULL");
}
Expand All @@ -3380,7 +3380,7 @@ public override async Task Select_expression_datetime_add_minute(bool isAsync)
await base.Select_expression_datetime_add_minute(isAsync);

AssertSql(
@"SELECT CAST(DATEADD(minute, CAST(1.0E0 AS int), [o].[OrderDate]) AS datetime2) AS [OrderDate]
@"SELECT DATEADD(minute, CAST(1.0E0 AS int), [o].[OrderDate]) AS [OrderDate]
FROM [Orders] AS [o]
WHERE [o].[OrderDate] IS NOT NULL");
}
Expand All @@ -3390,7 +3390,7 @@ public override async Task Select_expression_datetime_add_second(bool isAsync)
await base.Select_expression_datetime_add_second(isAsync);

AssertSql(
@"SELECT CAST(DATEADD(second, CAST(1.0E0 AS int), [o].[OrderDate]) AS datetime2) AS [OrderDate]
@"SELECT DATEADD(second, CAST(1.0E0 AS int), [o].[OrderDate]) AS [OrderDate]
FROM [Orders] AS [o]
WHERE [o].[OrderDate] IS NOT NULL");
}
Expand Down Expand Up @@ -3422,7 +3422,7 @@ public override async Task Select_expression_date_add_milliseconds_large_number_
AssertSql(
@"@__millisecondsPerDay_0='86400000'
SELECT CAST(DATEADD(millisecond, CAST(CAST((CAST(DATEPART(millisecond, [o].[OrderDate]) AS bigint) % @__millisecondsPerDay_0) AS float) AS int), DATEADD(day, CAST(CAST((CAST(DATEPART(millisecond, [o].[OrderDate]) AS bigint) / @__millisecondsPerDay_0) AS float) AS int), [o].[OrderDate])) AS datetime2) AS [OrderDate]
SELECT DATEADD(millisecond, CAST(CAST((CAST(DATEPART(millisecond, [o].[OrderDate]) AS bigint) % @__millisecondsPerDay_0) AS float) AS int), DATEADD(day, CAST(CAST((CAST(DATEPART(millisecond, [o].[OrderDate]) AS bigint) / @__millisecondsPerDay_0) AS float) AS int), [o].[OrderDate])) AS [OrderDate]
FROM [Orders] AS [o]
WHERE [o].[OrderDate] IS NOT NULL");
}
Expand Down Expand Up @@ -4877,6 +4877,17 @@ 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");
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public override async Task Convert_to_nullable_on_nullable_value_is_ignored(bool isAsync)
{
await base.Convert_to_nullable_on_nullable_value_is_ignored(isAsync);

AssertSql(
@"SELECT [o].[OrderDate]
FROM [Orders] AS [o]");
}

private void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);

Expand Down

0 comments on commit 17418aa

Please sign in to comment.