Skip to content

Commit

Permalink
Query: Use accurate generic types in group join flattening
Browse files Browse the repository at this point in the history
Resolves #27343
  • Loading branch information
smitpatel committed May 19, 2022
1 parent d69ba3c commit 57a540a
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -332,9 +332,9 @@ private Expression TryConvertEnumerableToQueryable(MethodCallExpression methodCa
|| innerQueryableElementType != genericType)
{
while (innerArgument is UnaryExpression
{
NodeType: ExpressionType.Convert or ExpressionType.ConvertChecked or ExpressionType.TypeAs
} unaryExpression
{
NodeType: ExpressionType.Convert or ExpressionType.ConvertChecked or ExpressionType.TypeAs
} unaryExpression
&& unaryExpression.Type.TryGetElementType(typeof(IEnumerable<>)) != null)
{
innerArgument = unaryExpression.Operand;
Expand Down Expand Up @@ -484,36 +484,12 @@ private Expression TryFlattenGroupJoinSelectMany(MethodCallExpression methodCall
resultSelectorBody,
groupJoinResultSelector.Parameters[0],
selectManyResultSelector.Parameters[1]);
var genericArguments = groupJoinMethod.Method.GetGenericArguments();
genericArguments[^1] = resultSelector.ReturnType;

// join case
if (defaultIfEmpty)
{
// left join
return Expression.Call(
QueryableExtensions.LeftJoinMethodInfo.MakeGenericMethod(
outer.Type.GetSequenceType(),
inner.Type.GetSequenceType(),
outerKeySelector.ReturnType,
resultSelector.ReturnType),
outer,
inner,
outerKeySelector,
innerKeySelector,
resultSelector);
}

// inner join
return Expression.Call(
QueryableMethods.Join.MakeGenericMethod(
outer.Type.GetSequenceType(),
inner.Type.GetSequenceType(),
outerKeySelector.ReturnType,
resultSelector.ReturnType),
outer,
inner,
outerKeySelector,
innerKeySelector,
resultSelector);
(defaultIfEmpty ? QueryableExtensions.LeftJoinMethodInfo : QueryableMethods.Join).MakeGenericMethod(genericArguments),
outer, inner, outerKeySelector, innerKeySelector, resultSelector);
}
// TODO: Convert correlated patterns to SelectMany
//else
Expand Down Expand Up @@ -599,35 +575,12 @@ private Expression TryFlattenGroupJoinSelectMany(MethodCallExpression methodCall
groupJoinResultSelector.Parameters[0],
innerKeySelector.Parameters[0]);

// join case
if (defaultIfEmpty)
{
// left join
return Expression.Call(
QueryableExtensions.LeftJoinMethodInfo.MakeGenericMethod(
outer.Type.GetSequenceType(),
inner.Type.GetSequenceType(),
outerKeySelector.ReturnType,
resultSelector.ReturnType),
outer,
inner,
outerKeySelector,
innerKeySelector,
resultSelector);
}
var genericArguments = groupJoinMethod.Method.GetGenericArguments();
genericArguments[^1] = resultSelector.ReturnType;

// inner join
return Expression.Call(
QueryableMethods.Join.MakeGenericMethod(
outer.Type.GetSequenceType(),
inner.Type.GetSequenceType(),
outerKeySelector.ReturnType,
resultSelector.ReturnType),
outer,
inner,
outerKeySelector,
innerKeySelector,
resultSelector);
(defaultIfEmpty ? QueryableExtensions.LeftJoinMethodInfo : QueryableMethods.Join).MakeGenericMethod(genericArguments),
outer, inner, outerKeySelector, innerKeySelector, resultSelector);
}
}
}
Expand Down
58 changes: 58 additions & 0 deletions test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1134,4 +1134,62 @@ protected class Child26744
public DateTime? SomeOtherNullableDateTime { get; set; }
public Parent26744 Parent { get; set; }
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Flattened_GroupJoin_on_interface_generic(bool async)
{
var contextFactory = await InitializeAsync<Context27343>(seed: c => c.Seed());
using var context = contextFactory.CreateContext();

var entitySet = context.Parents.AsQueryable<IDocumentType27343>();

var query = from p in entitySet
join c in context.Set<Child27343>()
on p.Id equals c.Id into grouping
from c in grouping.DefaultIfEmpty()
select c;

var result = async
? await query.ToListAsync()
: query.ToList();

Assert.Empty(result);
}

protected class Context27343 : DbContext
{
public Context27343(DbContextOptions options)
: base(options)
{
}

public DbSet<Parent27343> Parents { get; set; }

public void Seed()
{

SaveChanges();
}
}

protected interface IDocumentType27343
{
public int Id { get; }
}

protected class Parent27343 : IDocumentType27343
{
public int Id { get; set; }
public List<Child27343> Children { get; set; }
}

protected class Child27343
{
public int Id { get; set; }
public int SomeInteger { get; set; }
public DateTime? SomeNullableDateTime { get; set; }
public DateTime? SomeOtherNullableDateTime { get; set; }
public Parent27343 Parent { get; set; }
}
}

0 comments on commit 57a540a

Please sign in to comment.