Closed
Description
This is a regression introduced in v5.3.0
I have two different examples of how casting to object
and back to an interface of a mapped type cause errors. However they both happen only when one part of the query expression casts to object
and another part casts back to the interface of a mapped class. This leads me to think they may be closely related.
Prerequisites
- Mapped objects have interfaces defined and the Query and casts use the interfaces instead of the mapped types
- At some point the entities are cast to
object
and a later part of the query casts them back to the interface type
In our code this casting is done within code that is generating dynamic expressions and queries based on metadata, and hence needs to cast to object
at certain steps.
Problem
Casting back to the interface in a GroupBy
clause an expression reduction error
Example Code
var query = session.Query<ITimeChunk>()
.Select(x => new object[] { x })
.GroupBy(g => new object[] { ((ITimeChunk)g[0]).Issue.Project.Id }, v => (ITimeChunk)v[0])
.Select(r => new object[] { r.Key, r.Sum(t => (int?)t.Seconds) });
Error
Message:
System.ArgumentException : must be reducible node
Stack Trace:
Expression.ReduceAndCheck()
Expression.ReduceExtensions()
StackSpiller.RewriteExtensionExpression(Expression expr, Stack stack)
StackSpiller.RewriteExpression(Expression node, Stack stack)
StackSpiller.RewriteUnaryExpression(Expression expr, Stack stack)
StackSpiller.RewriteExpression(Expression node, Stack stack)
ChildRewriter.Add(Expression node)
ChildRewriter.Add(IList`1 expressions)
StackSpiller.RewriteNewArrayExpression(Expression expr, Stack stack)
StackSpiller.RewriteExpression(Expression node, Stack stack)
StackSpiller.RewriteExpressionFreeTemps(Expression expression, Stack stack)
StackSpiller.Rewrite[T](Expression`1 lambda)
Expression`1.Accept(StackSpiller spiller)
LambdaCompiler.Compile(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator)
Expression`1.Compile()
ExpressionToHqlTranslationResults.MergeLambdasAndCompile[TDelegate](IList`1 itemTransformers) line 55
ExpressionToHqlTranslationResults.ctor(HqlTreeNode statement, IList`1 itemTransformers, IList`1 listTransformers, IList`1 postExecuteTransformers, List`1 additionalCriteria, Type executeResultTypeOverride) line 33
IntermediateHqlTree.GetTranslation() line 100
QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root, Nullable`1 rootReturnType) line 106
NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory, Boolean filter) line 97
ASTQueryTranslatorFactory.CreateQueryTranslators(IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory) line 20
QueryExpressionPlan.CreateTranslators(IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) line 38
QueryExpressionPlan.ctor(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) line 20
QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters) line 63
AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow) line 584
AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression) line 552
DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query) line 208
DefaultQueryProvider.ExecuteList[TResult](Expression expression) line 107
IEnumerable<T>.GetEnumerator() line 65
List`1.ctor(IEnumerable`1 collection)
Enumerable.ToList[TSource](IEnumerable`1 source)