Skip to content
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
4 changes: 2 additions & 2 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"sdk": {
"version": "10.0.100-alpha.1.24573.1",
"version": "10.0.100-alpha.1.25059.31",
"allowPrerelease": true,
"rollForward": "latestMajor"
},
"tools": {
"dotnet": "10.0.100-alpha.1.24573.1",
"dotnet": "10.0.100-alpha.1.25059.31",
"runtimes": {
"dotnet": [
"$(MicrosoftNETCoreAppRuntimewinx64Version)"
Expand Down
32 changes: 0 additions & 32 deletions src/EFCore/Extensions/Internal/QueryableExtensions.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ protected Expression ExpandSkipNavigation(
secondaryExpansion = Expression.Call(
(innerJoin
? QueryableMethods.Join
: QueryableExtensions.LeftJoinMethodInfo).MakeGenericMethod(
: QueryableMethods.LeftJoin).MakeGenericMethod(
sourceElementType, innerSourceElementType,
outerKeySelector.ReturnType,
resultSelector.ReturnType),
Expand Down Expand Up @@ -462,7 +462,7 @@ outerKey is NewArrayExpression newArrayExpression
Expression.Call(
(innerJoin
? QueryableMethods.Join
: QueryableExtensions.LeftJoinMethodInfo).MakeGenericMethod(
: QueryableMethods.LeftJoin).MakeGenericMethod(
source.SourceElementType,
innerSource.SourceElementType,
outerKeySelector.ReturnType,
Expand Down Expand Up @@ -794,7 +794,7 @@ private Expression ExpandIncludesHelper(Expression root, EntityReference entityR
&& joinMethodCallExpression.Method.GetGenericMethodDefinition()
== (skipNavigation.Inverse.ForeignKey.IsRequired
? QueryableMethods.Join
: QueryableExtensions.LeftJoinMethodInfo)
: QueryableMethods.LeftJoin)
&& joinMethodCallExpression.Arguments[4] is UnaryExpression
{
NodeType: ExpressionType.Quote,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,9 +319,7 @@ protected override Expression VisitMember(MemberExpression memberExpression)
protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression)
{
var method = methodCallExpression.Method;
if (method.DeclaringType == typeof(Queryable)
|| method.DeclaringType == typeof(QueryableExtensions)
|| method.DeclaringType == typeof(EntityFrameworkQueryableExtensions))
if (method.DeclaringType == typeof(Queryable) || method.DeclaringType == typeof(EntityFrameworkQueryableExtensions))
{
var genericMethod = method.IsGenericMethod ? method.GetGenericMethodDefinition() : null;
// First argument is source
Expand Down Expand Up @@ -474,8 +472,8 @@ when QueryableMethods.IsSumWithSelector(method):
goto default;
}

case nameof(QueryableExtensions.LeftJoin)
when genericMethod == QueryableExtensions.LeftJoinMethodInfo:
case nameof(Queryable.LeftJoin)
when genericMethod == QueryableMethods.LeftJoin:
{
var secondArgument = Visit(methodCallExpression.Arguments[1]);
secondArgument = UnwrapCollectionMaterialization(secondArgument);
Expand Down Expand Up @@ -1312,7 +1310,7 @@ private NavigationExpansionExpression ProcessLeftJoin(
innerSource.CurrentParameter);

var source = Expression.Call(
QueryableExtensions.LeftJoinMethodInfo.MakeGenericMethod(
QueryableMethods.LeftJoin.MakeGenericMethod(
outerSource.SourceElementType, innerSource.SourceElementType, outerKeySelector.ReturnType,
newResultSelector.ReturnType),
outerSource.Source,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ when selectManyMethod.GetGenericMethodDefinition() == QueryableMethods.SelectMan
genericArguments[^1] = resultSelector.ReturnType;

return Expression.Call(
(defaultIfEmpty ? QueryableExtensions.LeftJoinMethodInfo : QueryableMethods.Join).MakeGenericMethod(
(defaultIfEmpty ? QueryableMethods.LeftJoin : QueryableMethods.Join).MakeGenericMethod(
genericArguments),
outer, inner, outerKeySelector, innerKeySelector, resultSelector);
}
Expand Down Expand Up @@ -726,7 +726,7 @@ when selectManyMethod.GetGenericMethodDefinition() == QueryableMethods.SelectMan
genericArguments[^1] = resultSelector.ReturnType;

return Expression.Call(
(defaultIfEmpty ? QueryableExtensions.LeftJoinMethodInfo : QueryableMethods.Join).MakeGenericMethod(
(defaultIfEmpty ? QueryableMethods.LeftJoin : QueryableMethods.Join).MakeGenericMethod(
genericArguments),
outer, inner, outerKeySelector, innerKeySelector, resultSelector);
}
Expand Down
1 change: 0 additions & 1 deletion src/EFCore/Query/QueryRootProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
var method = methodCallExpression.Method;
if (method.DeclaringType != typeof(Queryable)
&& method.DeclaringType != typeof(Enumerable)
&& method.DeclaringType != typeof(QueryableExtensions)
&& method.DeclaringType != typeof(EntityFrameworkQueryableExtensions))
{
return base.VisitMethodCall(methodCallExpression);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
}
}

if (method.DeclaringType == typeof(Queryable)
|| method.DeclaringType == typeof(QueryableExtensions))
if (method.DeclaringType == typeof(Queryable))
{
var source = Visit(methodCallExpression.Arguments[0]);
if (source is ShapedQueryExpression shapedQueryExpression)
Expand Down Expand Up @@ -394,8 +393,8 @@ when QueryableMethods.IsAverageWithSelector(method):
break;
}

case nameof(QueryableExtensions.LeftJoin)
when genericMethod == QueryableExtensions.LeftJoinMethodInfo:
case nameof(Queryable.LeftJoin)
when genericMethod == QueryableMethods.LeftJoin:
{
if (Visit(methodCallExpression.Arguments[1]) is ShapedQueryExpression innerShapedQueryExpression)
{
Expand Down
18 changes: 18 additions & 0 deletions src/EFCore/Query/QueryableMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,13 @@ public static class QueryableMethods
/// </summary>
public static MethodInfo LastOrDefaultWithPredicate { get; }

/// <summary>
/// The <see cref="MethodInfo" /> for
/// <see
/// cref="Queryable.LeftJoin{TOuter,TInner,TKey,TResult}(IQueryable{TOuter},IEnumerable{TInner},Expression{Func{TOuter,TKey}},Expression{Func{TInner,TKey}},Expression{Func{TOuter,TInner,TResult}})" />
/// </summary>
public static MethodInfo LeftJoin { get; }

/// <summary>
/// The <see cref="MethodInfo" /> for <see cref="Queryable.LongCount{TSource}(IQueryable{TSource})" />
/// </summary>
Expand Down Expand Up @@ -632,6 +639,17 @@ static QueryableMethods()
typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], typeof(bool)))
]);

LeftJoin = GetMethod(
nameof(Queryable.LeftJoin), 4,
types =>
[
typeof(IQueryable<>).MakeGenericType(types[0]),
typeof(IEnumerable<>).MakeGenericType(types[1]),
typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[0], types[2])),
typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(types[1], types[2])),
typeof(Expression<>).MakeGenericType(typeof(Func<,,>).MakeGenericType(types[0], types[1], types[3]))
]);

LongCountWithoutPredicate = GetMethod(
nameof(Queryable.LongCount), 1,
types => [typeof(IQueryable<>).MakeGenericType(types[0])]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,20 @@ on od.OrderID equals o.OrderID

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Delete_with_left_join(bool async)
public virtual Task Delete_with_LeftJoin(bool async)
=> AssertDelete(
async,
ss => ss.Set<OrderDetail>().Where(e => e.OrderID < 10276)
.LeftJoin(
ss.Set<Order>().Where(o => o.OrderID < 10300).OrderBy(e => e.OrderID).Skip(0).Take(100),
od => od.OrderID,
o => o.OrderID,
(od, o) => od),
rowsAffectedCount: 74);

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Delete_with_LeftJoin_via_flattened_GroupJoin(bool async)
=> AssertDelete(
async,
ss => from od in ss.Set<OrderDetail>().Where(e => e.OrderID < 10276)
Expand Down Expand Up @@ -820,7 +833,24 @@ on c.CustomerID equals o.CustomerID

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Update_with_left_join_set_constant(bool async)
public virtual Task Update_with_LeftJoin(bool async)
=> AssertUpdate(
async,
ss => ss
.Set<Customer>().Where(c => c.CustomerID.StartsWith("F"))
.LeftJoin(
ss.Set<Order>().Where(o => o.OrderID < 10300),
c => c.CustomerID,
o => o.CustomerID,
(c, o) => new { c, o }),
e => e.c,
s => s.SetProperty(c => c.c.ContactName, "Updated"),
rowsAffectedCount: 8,
(b, a) => Assert.All(a, c => Assert.Equal("Updated", c.ContactName)));

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Update_with_LeftJoin_via_flattened_GroupJoin(bool async)
=> AssertUpdate(
async,
ss => from c in ss.Set<Customer>().Where(c => c.CustomerID.StartsWith("F"))
Expand Down
36 changes: 19 additions & 17 deletions test/EFCore.Specification.Tests/CustomConvertersTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -435,23 +435,25 @@ public virtual async Task Value_conversion_is_appropriately_used_for_left_join_c
{
using var context = CreateContext();
var blogId = 1;
var query = await (from b in context.Set<Blog>()
join p in context.Set<Post>()
on new
{
BlogId = (int?)b.BlogId,
b.IsVisible,
AnotherId = b.BlogId
}
equals new
{
p.BlogId,
IsVisible = true,
AnotherId = blogId
} into g
from p in g.DefaultIfEmpty()
where b.IsVisible
select b.Url).ToListAsync();
var query = await context.Set<Blog>()
.LeftJoin(
context.Set<Post>(),
b => new
{
BlogId = (int?)b.BlogId,
b.IsVisible,
AnotherId = b.BlogId
},
p => new
{
p.BlogId,
IsVisible = true,
AnotherId = blogId
},
(b, p) => b)
.Where(b => b.IsVisible)
.Select(b => b.Url)
.ToListAsync();

var result = Assert.Single(query);
Assert.Equal("http://blog.com", result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,25 +64,25 @@ public class Product

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Left_join_with_missing_key_values_on_both_sides(bool async)
public virtual async Task LeftJoin_with_missing_key_values_on_both_sides(bool async)
{
var contextFactory = await InitializeAsync<Context6901>();
using var context = contextFactory.CreateContext();

var customers
= from customer in context.Customers
join postcode in context.Postcodes
on customer.PostcodeID equals postcode.PostcodeID into custPCTmp
from custPC in custPCTmp.DefaultIfEmpty()
select new
{
customer.CustomerID,
customer.CustomerName,
TownName = custPC == null ? string.Empty : custPC.TownName,
PostcodeValue = custPC == null ? string.Empty : custPC.PostcodeValue
};

var results = customers.ToList();
var results
= context.Customers
.LeftJoin(
context.Postcodes,
c => c.PostcodeID,
p => p.PostcodeID,
(c, p) => new
{
c.CustomerID,
c.CustomerName,
TownName = p == null ? string.Empty : p.TownName,
PostcodeValue = p == null ? string.Empty : p.PostcodeValue
})
.ToList();

Assert.Equal(5, results.Count);
Assert.True(results[3].CustomerName != results[4].CustomerName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -860,10 +860,9 @@ public virtual Task Entity_with_complex_type_with_group_by_and_first(bool async)
public virtual Task Projecting_property_of_complex_type_using_left_join_with_pushdown(bool async)
=> AssertQuery(
async,
ss => from cg in ss.Set<CustomerGroup>()
join c in ss.Set<Customer>().Where(x => x.Id > 5) on cg.Id equals c.Id into grouping
from c in grouping.DefaultIfEmpty()
select c == null ? null : (int?)c.BillingAddress.ZipCode);
ss => ss.Set<CustomerGroup>()
.LeftJoin(ss.Set<Customer>().Where(x => x.Id > 5), cg => cg.Id, c => c.Id, (cg, c) => c)
.Select(c => c == null ? null : (int?)c.BillingAddress.ZipCode));

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
Expand All @@ -880,10 +879,12 @@ public virtual Task Projecting_complex_from_optional_navigation_using_conditiona
public virtual Task Project_entity_with_complex_type_pushdown_and_then_left_join(bool async)
=> AssertQuery(
async,
ss => from c1 in ss.Set<Customer>().OrderBy(x => x.Id).Take(20).Distinct()
join c2 in ss.Set<Customer>().OrderByDescending(x => x.Id).Take(30).Distinct() on c1.Id equals c2.Id into grouping
from c2 in grouping.DefaultIfEmpty()
select new { Zip1 = c1.BillingAddress.ZipCode, Zip2 = c2.ShippingAddress.ZipCode });
ss => ss.Set<Customer>().OrderBy(x => x.Id).Take(20).Distinct()
.LeftJoin(
ss.Set<Customer>().OrderByDescending(x => x.Id).Take(30).Distinct(),
c1 => c1.Id,
c2 => c2.Id,
(c1, c2) => new { Zip1 = c1.BillingAddress.ZipCode, Zip2 = c2 == null ? (int?)null : c2.ShippingAddress.ZipCode }));

protected DbContext CreateContext()
=> Fixture.CreateContext();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,7 @@ public virtual Task Join_select_many(bool async)
ss => from c in ss.Set<Customer>().Where(c => c.CustomerID.StartsWith("F"))
join o in ss.Set<Order>() on c.CustomerID equals o.CustomerID
from e in ss.Set<Employee>()
select new
{
c,
o,
e
},
select new { c, o, e },
e => (e.c.CustomerID, e.o.OrderID, e.e.EmployeeID));

[ConditionalTheory]
Expand Down Expand Up @@ -297,6 +292,19 @@ public virtual Task Join_same_collection_force_alias_uniquefication(bool async)
ss.Set<Order>(), o => o.CustomerID, i => i.CustomerID, (_, o) => new { _, o }),
e => (e._.OrderID, e.o.OrderID));

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task LeftJoin(bool async)
=> AssertQuery(
async,
ss => ss.Set<Customer>()
.LeftJoin(
ss.Set<Order>(),
c => c.CustomerID,
o => o.CustomerID,
(c, o) => new { c, o }),
e => (e.c.CustomerID, e.o?.OrderID));

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task GroupJoin_customers_employees_shadow(bool async)
Expand Down
Loading