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 24, 2022
1 parent 176f301 commit 2809cd1
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 62 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
66 changes: 62 additions & 4 deletions test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,64 @@ protected class Child26744
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; }
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Pushdown_does_not_add_grouping_key_to_projection_when_distinct_is_applied(bool async)
Expand Down Expand Up @@ -1172,7 +1230,7 @@ public Context28039(DbContextOptions options)
public DbSet<TableData> TableData { get; set; }
}

public class TableData : EntityBase
protected class TableData : EntityBase
{
public int TableId { get; set; }
public string ParcelNumber { get; set; }
Expand All @@ -1181,18 +1239,18 @@ public class TableData : EntityBase

}

public abstract class EntityBase
protected abstract class EntityBase
{
[Key]
public int ID { get; set; }
}
public class IndexData : EntityBase
protected class IndexData : EntityBase
{
public string Parcel { get; set; }
public int RowId { get; set; }
}

internal class SearchResult
protected class SearchResult
{
public string ParcelNumber { get; set; }
public int RowId { get; set; }
Expand Down

0 comments on commit 2809cd1

Please sign in to comment.