Skip to content

Commit f47b06d

Browse files
committed
Add support for MemberInit expression in GroupBySelectClauseRewriter (nhibernate#2221)
1 parent d4e3a54 commit f47b06d

File tree

3 files changed

+101
-2
lines changed

3 files changed

+101
-2
lines changed

src/NHibernate.Test/Async/Linq/ByMethod/GroupByTests.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,48 @@ public async Task GroupByOrderByKeySelectToClassAsync()
910910
.ToListAsync());
911911
}
912912

913+
[Test]
914+
public async Task SelectArrayIndexBeforeGroupByAsync()
915+
{
916+
var result = db.Orders
917+
.SelectMany(o => o.OrderLines.Select(c => c.Id).DefaultIfEmpty().Select(c => new object[] {c, o}))
918+
.GroupBy(g => g[0], g => (Order) g[1])
919+
.Select(g => new[] {g.Key, g.Count(), g.Max(x => x.OrderDate)});
920+
921+
Assert.True(await (result.AnyAsync()));
922+
}
923+
924+
[Test]
925+
public async Task SelectMemberInitBeforeGroupByAsync()
926+
{
927+
var result = await (db.Orders
928+
.Select(o => new OrderGroup {OrderId = o.OrderId, OrderDate = o.OrderDate})
929+
.GroupBy(o => o.OrderId)
930+
.Select(g => new OrderGroup {OrderId = g.Key, OrderDate = g.Max(o => o.OrderDate)})
931+
.ToListAsync());
932+
933+
Assert.True(result.Any());
934+
}
935+
936+
[Test]
937+
public async Task SelectNewBeforeGroupByAsync()
938+
{
939+
var result = await (db.Orders
940+
.Select(o => new {o.OrderId, o.OrderDate})
941+
.GroupBy(o => o.OrderId)
942+
.Select(g => new {OrderId = g.Key, OrderDate = g.Max(o => o.OrderDate)})
943+
.ToListAsync());
944+
945+
Assert.True(result.Any());
946+
}
947+
948+
private class OrderGroup
949+
{
950+
public int OrderId { get; set; }
951+
952+
public DateTime? OrderDate { get; set; }
953+
}
954+
913955
private class GroupInfo
914956
{
915957
public object Key { get; set; }

src/NHibernate.Test/Linq/ByMethod/GroupByTests.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,48 @@ public void FetchBeforeGroupBy()
912912
Assert.True(result.Any());
913913
}
914914

915+
[Test]
916+
public void SelectArrayIndexBeforeGroupBy()
917+
{
918+
var result = db.Orders
919+
.SelectMany(o => o.OrderLines.Select(c => c.Id).DefaultIfEmpty().Select(c => new object[] {c, o}))
920+
.GroupBy(g => g[0], g => (Order) g[1])
921+
.Select(g => new[] {g.Key, g.Count(), g.Max(x => x.OrderDate)});
922+
923+
Assert.True(result.Any());
924+
}
925+
926+
[Test]
927+
public void SelectMemberInitBeforeGroupBy()
928+
{
929+
var result = db.Orders
930+
.Select(o => new OrderGroup {OrderId = o.OrderId, OrderDate = o.OrderDate})
931+
.GroupBy(o => o.OrderId)
932+
.Select(g => new OrderGroup {OrderId = g.Key, OrderDate = g.Max(o => o.OrderDate)})
933+
.ToList();
934+
935+
Assert.True(result.Any());
936+
}
937+
938+
[Test]
939+
public void SelectNewBeforeGroupBy()
940+
{
941+
var result = db.Orders
942+
.Select(o => new {o.OrderId, o.OrderDate})
943+
.GroupBy(o => o.OrderId)
944+
.Select(g => new {OrderId = g.Key, OrderDate = g.Max(o => o.OrderDate)})
945+
.ToList();
946+
947+
Assert.True(result.Any());
948+
}
949+
950+
private class OrderGroup
951+
{
952+
public int OrderId { get; set; }
953+
954+
public DateTime? OrderDate { get; set; }
955+
}
956+
915957
private class GroupInfo
916958
{
917959
public object Key { get; set; }

src/NHibernate/Linq/GroupBy/GroupBySelectClauseRewriter.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using System.Linq.Expressions;
45
using NHibernate.Linq.Expressions;
@@ -14,6 +15,13 @@ namespace NHibernate.Linq.GroupBy
1415
//This should be renamed. It handles entire querymodels, not just select clauses
1516
internal class GroupBySelectClauseRewriter : RelinqExpressionVisitor
1617
{
18+
private readonly static HashSet<ExpressionType> _validElementSelectorTypes = new HashSet<ExpressionType>
19+
{
20+
ExpressionType.ArrayIndex,
21+
ExpressionType.New,
22+
ExpressionType.MemberInit
23+
};
24+
1725
public static Expression ReWrite(Expression expression, GroupResultOperator groupBy, QueryModel model)
1826
{
1927
var visitor = new GroupBySelectClauseRewriter(groupBy, model);
@@ -67,8 +75,8 @@ protected override Expression VisitMember(MemberExpression expression)
6775
return base.VisitMember(expression);
6876
}
6977

70-
if ((elementSelector is NewExpression || elementSelector.NodeType == ExpressionType.Convert)
71-
&& elementSelector.Type == expression.Expression.Type)
78+
if (_validElementSelectorTypes.Contains(UnwrapUnary(elementSelector).NodeType) &&
79+
elementSelector.Type == expression.Expression.Type)
7280
{
7381
//TODO: probably we should check this with a visitor
7482
return Expression.MakeMemberAccess(elementSelector, expression.Member);
@@ -156,5 +164,12 @@ expression.QueryModel.SelectClause.Selector is NhCountExpression countExpression
156164
// valid assumption. Should probably be passed a list of aggregating subqueries that we are flattening so that we can check...
157165
return ReWrite(expression.QueryModel.SelectClause.Selector, _groupBy, _model);
158166
}
167+
168+
private static Expression UnwrapUnary(Expression expression)
169+
{
170+
return expression is UnaryExpression unaryExpression
171+
? unaryExpression.Operand
172+
: expression;
173+
}
159174
}
160175
}

0 commit comments

Comments
 (0)