Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore convert nodes from nullable to non-nullable #16746

Merged
merged 1 commit into from
Jul 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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