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

Query: Handle multiple lets with weak entities #22259

Merged
1 commit merged into from
Aug 27, 2020
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 @@ -1337,6 +1337,7 @@ protected override Expression VisitExtension(Expression extensionExpression)
Check.NotNull(extensionExpression, nameof(extensionExpression));

return extensionExpression is EntityShaperExpression
|| extensionExpression is ShapedQueryExpression
? extensionExpression
: base.VisitExtension(extensionExpression);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1280,6 +1280,7 @@ protected override Expression VisitExtension(Expression extensionExpression)
Check.NotNull(extensionExpression, nameof(extensionExpression));

return extensionExpression is EntityShaperExpression
|| extensionExpression is ShapedQueryExpression
? extensionExpression
: base.VisitExtension(extensionExpression);
}
Expand Down
4 changes: 3 additions & 1 deletion src/EFCore/Query/ReplacingExpressionVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ public ReplacingExpressionVisitor([NotNull] IReadOnlyList<Expression> originals,
/// <inheritdoc />
public override Expression Visit(Expression expression)
{
if (expression == null)
if (expression == null
|| expression is ShapedQueryExpression
|| expression is EntityShaperExpression)
{
return expression;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5538,7 +5538,8 @@ public virtual Task Member_over_null_check_ternary_and_nested_dto_type(bool asyn
? null
: new Level2Dto
{
Id = l1.OneToOne_Optional_FK1.Id, Name = l1.OneToOne_Optional_FK1.Name,
Id = l1.OneToOne_Optional_FK1.Id,
Name = l1.OneToOne_Optional_FK1.Name,
}
})
.OrderBy(e => e.Level2.Name)
Expand Down Expand Up @@ -5645,5 +5646,26 @@ where l1.Id < 3
orderby l3.Id
select l3).Distinct().Take(1).OrderBy(e => e.Id).FirstOrDefault().Name);
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Let_let_contains_from_outer_let(bool async)
{
return AssertQuery(
async,
ss => from l1 in ss.Set<Level1>().Include(l => l.OneToMany_Required1)
let level2Ids = from level2 in l1.OneToMany_Required1 select level2.Id
let level3s = (from level3 in ss.Set<Level3>()
where level2Ids.Contains(level3.Level2_Required_Id)
select level3).AsEnumerable()
from level3 in level3s.DefaultIfEmpty()
select new { l1, level3 },
elementSorter: e => (e.l1.Id, e.level3?.Id),
elementAsserter: (e, a) =>
{
AssertEqual(e.l1, a.l1);
AssertEqual(e.level3, a.level3);
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5897,6 +5897,25 @@ FROM [LevelOne] AS [l0]
WHERE [l0].[Id] < 3");
}

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

AssertSql(
@"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id], [t].[Id], [t].[Level2_Optional_Id], [t].[Level2_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse3Id], [t].[OneToMany_Optional_Self_Inverse3Id], [t].[OneToMany_Required_Inverse3Id], [t].[OneToMany_Required_Self_Inverse3Id], [t].[OneToOne_Optional_PK_Inverse3Id], [t].[OneToOne_Optional_Self3Id], [l2].[Id], [l2].[Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Name], [l2].[OneToMany_Optional_Inverse2Id], [l2].[OneToMany_Optional_Self_Inverse2Id], [l2].[OneToMany_Required_Inverse2Id], [l2].[OneToMany_Required_Self_Inverse2Id], [l2].[OneToOne_Optional_PK_Inverse2Id], [l2].[OneToOne_Optional_Self2Id]
FROM [LevelOne] AS [l]
OUTER APPLY (
SELECT [l0].[Id], [l0].[Level2_Optional_Id], [l0].[Level2_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse3Id], [l0].[OneToMany_Optional_Self_Inverse3Id], [l0].[OneToMany_Required_Inverse3Id], [l0].[OneToMany_Required_Self_Inverse3Id], [l0].[OneToOne_Optional_PK_Inverse3Id], [l0].[OneToOne_Optional_Self3Id]
FROM [LevelThree] AS [l0]
WHERE EXISTS (
SELECT 1
FROM [LevelTwo] AS [l1]
WHERE ([l].[Id] = [l1].[OneToMany_Required_Inverse2Id]) AND ([l1].[Id] = [l0].[Level2_Required_Id]))
) AS [t]
LEFT JOIN [LevelTwo] AS [l2] ON [l].[Id] = [l2].[OneToMany_Required_Inverse2Id]
ORDER BY [l].[Id], [t].[Id], [l2].[Id]");
}

private void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// 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.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Sqlite.Internal;
using Xunit;

namespace Microsoft.EntityFrameworkCore.Query
Expand All @@ -19,36 +21,72 @@ public override Task Include_inside_subquery(bool async)
return base.Include_inside_subquery(async);
}

// Sqlite does not support cross/outer apply
public override Task Filtered_include_after_different_filtered_include_different_level(bool async)
=> null;
public override async Task Filtered_include_after_different_filtered_include_different_level(bool async)
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Filtered_include_after_different_filtered_include_different_level(async))).Message);

public override void Filtered_include_outer_parameter_used_inside_filter() { }
public override void Filtered_include_outer_parameter_used_inside_filter()
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
Assert.Throws<InvalidOperationException>(
() => base.Filtered_include_outer_parameter_used_inside_filter()).Message);

public override Task Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(bool async)
=> null;
public override async Task Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(bool async)
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(async))).Message);

public override Task Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(
public override async Task Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(
bool async)
=> null;
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(async))).Message);

public override Task Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(bool async)
=> null;
public override async Task Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(bool async)
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(async))).Message);

public override Task Filtered_include_complex_three_level_with_middle_having_filter1(bool async)
=> null;
public override async Task Filtered_include_complex_three_level_with_middle_having_filter1(bool async)
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Filtered_include_complex_three_level_with_middle_having_filter1(async))).Message);

public override Task Filtered_include_complex_three_level_with_middle_having_filter2(bool async)
=> null;
public override async Task Filtered_include_complex_three_level_with_middle_having_filter2(bool async)
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Filtered_include_complex_three_level_with_middle_having_filter2(async))).Message);

public override Task Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation_split(bool async)
=> null;
public override async Task Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation_split(bool async)
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation_split(async))).Message);

public override Task
public override async Task
Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only_split(bool async)
=> null;
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only_split(async))).Message);

public override Task Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes_split(bool async)
=> null;
public override async Task Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes_split(bool async)
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes_split(async))).Message);

public override async Task Let_let_contains_from_outer_let(bool async)
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Let_let_contains_from_outer_let(async))).Message);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// 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.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Sqlite.Internal;
using Xunit;
using Xunit.Abstractions;

namespace Microsoft.EntityFrameworkCore.Query
Expand All @@ -14,24 +17,47 @@ public ComplexNavigationsWeakQuerySqliteTest(ComplexNavigationsWeakQuerySqliteFi
{
}

// Sqlite does not support cross/outer apply
public override Task Filtered_include_after_different_filtered_include_different_level(bool async)
=> null;

public override Task Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(bool async)
=> null;

public override Task Filtered_include_complex_three_level_with_middle_having_filter1(bool async)
=> null;

public override Task Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(
public override async Task Filtered_include_after_different_filtered_include_different_level(bool async)
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Filtered_include_after_different_filtered_include_different_level(async))).Message);

public override async Task Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(bool async)
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(async))).Message);

public override async Task Filtered_include_complex_three_level_with_middle_having_filter1(bool async)
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Filtered_include_complex_three_level_with_middle_having_filter1(async))).Message);

public override async Task Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(
bool async)
=> null;

public override Task Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(bool async)
=> null;

public override Task Filtered_include_complex_three_level_with_middle_having_filter2(bool async)
=> null;
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(async))).Message);

public override async Task Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(bool async)
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(async))).Message);

public override async Task Filtered_include_complex_three_level_with_middle_having_filter2(bool async)
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Filtered_include_complex_three_level_with_middle_having_filter2(async))).Message);

public override async Task Let_let_contains_from_outer_let(bool async)
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
(await Assert.ThrowsAsync<InvalidOperationException>(
() => base.Let_let_contains_from_outer_let(async))).Message);
}
}