Skip to content

NH 3797 #432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 23, 2015
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
21 changes: 21 additions & 0 deletions src/NHibernate.Test/Linq/ByMethod/GroupByTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,27 @@ into grp
Assert.That(result.Count, Is.EqualTo(77));
}

[Test(Description = "NH-3797")]
public void GroupByComputedValue()
{
var orderGroups = db.Orders.GroupBy(o => o.Customer.CustomerId == null ? 0 : 1).Select(g => new { Key = g.Key, Count = g.Count() }).ToList();
Assert.AreEqual(830, orderGroups.Sum(g => g.Count));
}

[Test(Description = "NH-3797")]
public void GroupByComputedValueInAnonymousType()
{
var orderGroups = db.Orders.GroupBy(o => new { Key = o.Customer.CustomerId == null ? 0 : 1 }).Select(g => new { Key = g.Key, Count = g.Count() }).ToList();
Assert.AreEqual(830, orderGroups.Sum(g => g.Count));
}

[Test(Description = "NH-3797")]
public void GroupByComputedValueInObjectArray()
{
var orderGroups = db.Orders.GroupBy(o => new[] { o.Customer.CustomerId == null ? 0 : 1, }).Select(g => new { Key = g.Key, Count = g.Count() }).ToList();
Assert.AreEqual(830, orderGroups.Sum(g => g.Count));
}

private static void CheckGrouping<TKey, TElement>(IEnumerable<IGrouping<TKey, TElement>> groupedItems, Func<TElement, TKey> groupBy)
{
var used = new HashSet<object>();
Expand Down
7 changes: 5 additions & 2 deletions src/NHibernate/Linq/GroupBy/AggregatingGroupByRewriter.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using NHibernate.Linq.Clauses;
using NHibernate.Linq.ReWriters;
using NHibernate.Linq.Visitors;
using NHibernate.Util;
using Remotion.Linq;
using Remotion.Linq.Clauses.Expressions;
using Remotion.Linq.Clauses.ResultOperators;
Expand Down Expand Up @@ -42,7 +44,7 @@ public static class AggregatingGroupByRewriter
typeof (CacheableResultOperator)
};

public static void ReWrite(QueryModel queryModel)
public static void ReWrite(QueryModel queryModel, IList<Expression> groupByKeys)
{
var subQueryExpression = queryModel.MainFromClause.FromExpression as SubQueryExpression;

Expand All @@ -57,6 +59,7 @@ public static void ReWrite(QueryModel queryModel)
var groupBy = operators[0] as GroupResultOperator;
if (groupBy != null)
{
groupBy.ExtractKeyExpressions(groupByKeys);
FlattenSubQuery(queryModel, subQueryExpression.QueryModel, groupBy);
}
}
Expand Down Expand Up @@ -91,7 +94,7 @@ private static void FlattenSubQuery(QueryModel queryModel, QueryModel subQueryMo
queryModel.BodyClauses.Add(bodyClause);

// Replace the outer select clause...
queryModel.SelectClause.TransformExpressions(s =>
queryModel.SelectClause.TransformExpressions(s =>
GroupBySelectClauseRewriter.ReWrite(s, groupBy, subQueryModel));

// Point all query source references to the outer from clause
Expand Down
23 changes: 23 additions & 0 deletions src/NHibernate/Linq/GroupResultOperatorExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using NHibernate.Util;
using Remotion.Linq.Clauses.ResultOperators;

namespace NHibernate.Linq
{
internal static class GroupResultOperatorExtensions
{
public static void ExtractKeyExpressions(this GroupResultOperator groupResult, IList<Expression> groupByKeys)
{
if (groupResult.KeySelector is NewExpression)
(groupResult.KeySelector as NewExpression).Arguments.ForEach(groupByKeys.Add);
else if (groupResult.KeySelector is NewArrayExpression)
(groupResult.KeySelector as NewArrayExpression).Expressions.ForEach(groupByKeys.Add);
else
groupByKeys.Add(groupResult.KeySelector);
}
}
}
11 changes: 8 additions & 3 deletions src/NHibernate/Linq/Visitors/QueryModelVisitor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using NHibernate.Hql.Ast;
using NHibernate.Linq.Clauses;
Expand Down Expand Up @@ -32,7 +34,7 @@ public static ExpressionToHqlTranslationResults GenerateHqlQuery(QueryModel quer
NonAggregatingGroupByRewriter.ReWrite(queryModel);

// Rewrite aggregate group-by statements
AggregatingGroupByRewriter.ReWrite(queryModel);
AggregatingGroupByRewriter.ReWrite(queryModel, parameters.GroupByKeys);

// Rewrite aggregating group-joins
AggregatingGroupJoinRewriter.ReWrite(queryModel);
Expand Down Expand Up @@ -74,7 +76,10 @@ public static ExpressionToHqlTranslationResults GenerateHqlQuery(QueryModel quer
// Identify and name query sources
QuerySourceIdentifier.Visit(parameters.QuerySourceNamer, queryModel);

var visitor = new QueryModelVisitor(parameters, root, queryModel) { RewrittenOperatorResult = result };
var visitor = new QueryModelVisitor(parameters, root, queryModel)
{
RewrittenOperatorResult = result,
};
visitor.Visit();

return visitor._hqlTree.GetTranslation();
Expand Down Expand Up @@ -230,7 +235,7 @@ public override void VisitSelectClause(SelectClause selectClause, QueryModel que
{
CurrentEvaluationType = selectClause.GetOutputDataInfo();

var visitor = new SelectClauseVisitor(typeof(object[]), VisitorParameters);
var visitor = new SelectClauseVisitor(typeof(object[]), VisitorParameters, VisitorParameters.GroupByKeys);

visitor.Visit(selectClause.Selector);

Expand Down
5 changes: 3 additions & 2 deletions src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ public class SelectClauseVisitor : ExpressionTreeVisitor
private List<HqlExpression> _hqlTreeNodes = new List<HqlExpression>();
private readonly HqlGeneratorExpressionTreeVisitor _hqlVisitor;

public SelectClauseVisitor(System.Type inputType, VisitorParameters parameters)
public SelectClauseVisitor(System.Type inputType, VisitorParameters parameters, IEnumerable<Expression> groupByKeys)
{
_inputParameter = Expression.Parameter(inputType, "input");
_parameters = parameters;
_hqlVisitor = new HqlGeneratorExpressionTreeVisitor(_parameters);
_hqlNodes = new HashSet<Expression>(groupByKeys);
}

public LambdaExpression ProjectionExpression { get; private set; }
Expand All @@ -43,7 +44,7 @@ public void Visit(Expression expression)
// Find the sub trees that can be expressed purely in HQL
var nominator = new SelectClauseHqlNominator(_parameters);
nominator.Visit(expression);
_hqlNodes = nominator.HqlCandidates;
_hqlNodes.UnionWith(nominator.HqlCandidates);

// Linq2SQL ignores calls to local methods. Linq2EF seems to not support
// calls to local methods at all. For NHibernate we support local methods,
Expand Down
3 changes: 3 additions & 0 deletions src/NHibernate/Linq/Visitors/VisitorParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class VisitorParameters

public QuerySourceNamer QuerySourceNamer { get; set; }

public IList<Expression> GroupByKeys { get; private set; }

public VisitorParameters(
ISessionFactoryImplementor sessionFactory,
IDictionary<ConstantExpression, NamedParameter> constantToParameterMap,
Expand All @@ -26,6 +28,7 @@ public VisitorParameters(
ConstantToParameterMap = constantToParameterMap;
RequiredHqlParameters = requiredHqlParameters;
QuerySourceNamer = querySourceNamer;
GroupByKeys = new List<Expression>();
}
}
}
1 change: 1 addition & 0 deletions src/NHibernate/NHibernate.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@
<Compile Include="Linq\Functions\EqualsGenerator.cs" />
<Compile Include="Linq\GroupBy\KeySelectorVisitor.cs" />
<Compile Include="Linq\GroupBy\PagingRewriter.cs" />
<Compile Include="Linq\GroupResultOperatorExtensions.cs" />
<Compile Include="Linq\NestedSelects\NestedSelectDetector.cs" />
<Compile Include="Linq\NestedSelects\Tuple.cs" />
<Compile Include="Linq\NestedSelects\SelectClauseRewriter.cs" />
Expand Down