Skip to content

Casting to object and back to interface in GroupBy causes error #2857

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

Closed
PleasantD opened this issue Jul 14, 2021 · 4 comments
Closed

Casting to object and back to interface in GroupBy causes error #2857

PleasantD opened this issue Jul 14, 2021 · 4 comments

Comments

@PleasantD
Copy link
Contributor

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)
@PleasantD
Copy link
Contributor Author

Unit test of the above example.
GH2857.zip

This may be related to #2858

@bahusoid
Copy link
Member

bahusoid commented Aug 2, 2021

.Select(r => new object[] { r.Key, r.Sum(t => (int?)t.Seconds) })

Seconds is unmapped property in your sample.

@PleasantD
Copy link
Contributor Author

Hmm... a small error.
I added the property mapping and the same error occurs when run on the 5.3.0 - 5.3.9 releases
GH2857_fixed.zip

Although, as I predicted fixing #2858 (via PR #2879) also fixed this issue.

It may still be beneficial to include these tests though.

@bahusoid
Copy link
Member

bahusoid commented Aug 9, 2021

It may still be beneficial to include these tests though.

Bu you've added tests in #2858 that seems to cover this scenario. Feel free to add more tests if you think that's not enough:
https://github.com/nhibernate/nhibernate-core/blob/5.3.x/src/NHibernate.Test/NHSpecificTest/GH2858/FixtureByCode.cs#L111-L139

So closing as duplicate of #2858

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants