Skip to content

Commit 267e226

Browse files
authored
Add support for nested non aggregating group by operators (#3087)
Fixes #3076
1 parent 5b3d8e2 commit 267e226

File tree

5 files changed

+74
-16
lines changed

5 files changed

+74
-16
lines changed

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,29 @@ public async Task GroupByComputedValueFromNestedObjectSelectAsync()
851851
Assert.AreEqual(2155, orderGroups.Sum(g => g.Count));
852852
}
853853

854+
[Test(Description="GH-3076")]
855+
public async Task NestedNonAggregateGroupByAsync()
856+
{
857+
var list = await (db.OrderLines
858+
.GroupBy(x => new { x.Order.OrderId, x.Product.ProductId }) // this works fine
859+
.GroupBy(x => x.Key.ProductId) // exception: "A recognition error occurred"
860+
.ToListAsync());
861+
862+
Assert.That(list, Has.Count.EqualTo(77));
863+
}
864+
865+
[Test(Description="GH-3076")]
866+
public async Task NestedNonAggregateGroupBySelectAsync()
867+
{
868+
var list = await (db.OrderLines
869+
.GroupBy(x => new { x.Order.OrderId, x.Product.ProductId }) // this works fine
870+
.GroupBy(x => x.Key.ProductId) // exception: "A recognition error occurred"
871+
.Select(x => new { ProductId = x })
872+
.ToListAsync());
873+
874+
Assert.That(list, Has.Count.EqualTo(77));
875+
}
876+
854877
private static void CheckGrouping<TKey, TElement>(IEnumerable<IGrouping<TKey, TElement>> groupedItems, Func<TElement, TKey> groupBy)
855878
{
856879
var used = new HashSet<object>();

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,29 @@ public void GroupByComputedValueFromNestedObjectSelect()
840840
Assert.AreEqual(2155, orderGroups.Sum(g => g.Count));
841841
}
842842

843+
[Test(Description="GH-3076")]
844+
public void NestedNonAggregateGroupBy()
845+
{
846+
var list = db.OrderLines
847+
.GroupBy(x => new { x.Order.OrderId, x.Product.ProductId }) // this works fine
848+
.GroupBy(x => x.Key.ProductId) // exception: "A recognition error occurred"
849+
.ToList();
850+
851+
Assert.That(list, Has.Count.EqualTo(77));
852+
}
853+
854+
[Test(Description="GH-3076")]
855+
public void NestedNonAggregateGroupBySelect()
856+
{
857+
var list = db.OrderLines
858+
.GroupBy(x => new { x.Order.OrderId, x.Product.ProductId }) // this works fine
859+
.GroupBy(x => x.Key.ProductId) // exception: "A recognition error occurred"
860+
.Select(x => new { ProductId = x })
861+
.ToList();
862+
863+
Assert.That(list, Has.Count.EqualTo(77));
864+
}
865+
843866
private static void CheckGrouping<TKey, TElement>(IEnumerable<IGrouping<TKey, TElement>> groupedItems, Func<TElement, TKey> groupBy)
844867
{
845868
var used = new HashSet<object>();

src/NHibernate/Linq/GroupBy/NonAggregatingGroupByRewriter.cs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Linq;
23
using System.Linq.Expressions;
34
using NHibernate.Linq.ResultOperators;
45
using Remotion.Linq;
@@ -13,22 +14,23 @@ public static class NonAggregatingGroupByRewriter
1314
{
1415
public static void ReWrite(QueryModel queryModel)
1516
{
16-
if (queryModel.ResultOperators.Count == 1
17-
&& queryModel.ResultOperators[0] is GroupResultOperator
17+
if (queryModel.ResultOperators.Count > 0
18+
&& queryModel.ResultOperators.All(r => r is GroupResultOperator)
1819
&& IsNonAggregatingGroupBy(queryModel))
1920
{
20-
var resultOperator = (GroupResultOperator)queryModel.ResultOperators[0];
21-
queryModel.ResultOperators.Clear();
22-
queryModel.ResultOperators.Add(new NonAggregatingGroupBy(resultOperator));
21+
for (var i = 0; i < queryModel.ResultOperators.Count; i++)
22+
{
23+
var resultOperator = (GroupResultOperator) queryModel.ResultOperators[i];
24+
queryModel.ResultOperators[i] = new NonAggregatingGroupBy(resultOperator);
25+
}
26+
2327
return;
2428
}
2529

26-
var subQueryExpression = queryModel.MainFromClause.FromExpression as SubQueryExpression;
27-
28-
if ((subQueryExpression != null)
29-
&& (subQueryExpression.QueryModel.ResultOperators.Count == 1)
30-
&& (subQueryExpression.QueryModel.ResultOperators[0] is GroupResultOperator)
31-
&& (IsNonAggregatingGroupBy(queryModel)))
30+
if (queryModel.MainFromClause.FromExpression is SubQueryExpression subQueryExpression
31+
&& subQueryExpression.QueryModel.ResultOperators.Count > 0
32+
&& subQueryExpression.QueryModel.ResultOperators.All(r => r is GroupResultOperator)
33+
&& IsNonAggregatingGroupBy(queryModel))
3234
{
3335
FlattenSubQuery(subQueryExpression, queryModel);
3436
}
@@ -58,7 +60,12 @@ private static void FlattenSubQuery(SubQueryExpression subQueryExpression, Query
5860
throw new NotImplementedException();
5961
}
6062

61-
queryModel.ResultOperators.Add(new NonAggregatingGroupBy((GroupResultOperator) subQueryModel.ResultOperators[0]));
63+
for (var i = 0; i < subQueryModel.ResultOperators.Count; i++)
64+
{
65+
var resultOperator = new NonAggregatingGroupBy((GroupResultOperator) subQueryModel.ResultOperators[i]);
66+
queryModel.ResultOperators.Add(resultOperator);
67+
}
68+
6269
queryModel.ResultOperators.Add(clientSideSelect);
6370
}
6471

@@ -103,4 +110,4 @@ public ClientSideSelect2(LambdaExpression selectClause)
103110
SelectClause = selectClause;
104111
}
105112
}
106-
}
113+
}

src/NHibernate/Linq/ResultOperators/NonAggregatingGroupBy.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Remotion.Linq.Clauses.ResultOperators;
2+
using Remotion.Linq.Clauses.StreamedData;
23

34
namespace NHibernate.Linq.ResultOperators
45
{
@@ -9,6 +10,9 @@ public NonAggregatingGroupBy(GroupResultOperator groupBy)
910
GroupBy = groupBy;
1011
}
1112

12-
public GroupResultOperator GroupBy { get; private set; }
13+
public GroupResultOperator GroupBy { get; }
14+
15+
public override IStreamedDataInfo GetOutputDataInfo(IStreamedDataInfo inputInfo) =>
16+
GroupBy.GetOutputDataInfo(inputInfo);
1317
}
14-
}
18+
}

src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessNonAggregatingGroupBy.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
using NHibernate.Linq.ResultOperators;
55
using NHibernate.Util;
66
using Remotion.Linq.Clauses.ExpressionVisitors;
7+
using Remotion.Linq.Clauses.StreamedData;
78

89
namespace NHibernate.Linq.Visitors.ResultOperatorProcessors
910
{
1011
public class ProcessNonAggregatingGroupBy : IResultOperatorProcessor<NonAggregatingGroupBy>
1112
{
1213
public void Process(NonAggregatingGroupBy resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree)
1314
{
14-
var selector = queryModelVisitor.Model.SelectClause.Selector;
15+
var selector = ((StreamedSequenceInfo) queryModelVisitor.PreviousEvaluationType).ItemExpression;
1516
var keySelector = resultOperator.GroupBy.KeySelector;
1617
var elementSelector = resultOperator.GroupBy.ElementSelector;
1718

0 commit comments

Comments
 (0)