nhibernate-core icon indicating copy to clipboard operation
nhibernate-core copied to clipboard

Linq query OrderBy fails when projecting to record type class having primary constructor

Open ninkasi99 opened this issue 2 years ago • 7 comments

NHibernate Linq fails to convert OrderBy expression to SQL when projecting to a record type class that has a primary constructor. If I remove the primary constructor of the class I am projecting to then the OrderBy expression works.

//OrderBy fails if object projecting to has primary constructor:
public record SearchCoursesResult(
    Guid CourseId,
    string CourseName,
    Guid SubjectId,
    string SubjectName,
    string CourseLevel,
    string? CollegeCourseCode,
    bool CourseIsActive
    );

//OrderBy succeeds if object projecting to does not have primary constructor
public record SearchCoursesResult
{
    public Guid CourseId { get; init; }
    public string CourseName { get; init; }    
    public Guid SubjectId { get; init; }    
    public string SubjectName { get; init; }    
    public string CourseLevel { get; init; }    
    public string? CollegeCourseCode { get; init; }    
    public bool CourseIsActive { get; init; }
}

ninkasi99 avatar Dec 20 '22 17:12 ninkasi99

This fails:

var projection = query.Select(c => new SearchCoursesResult(
            c.Id,
            c.Name,
            c.Subject.Id,
            c.Subject.Name,
            c.Level,
            c.CollegeCourseCode,
            c.IsActive
        ));
projection.OrderBy(c => c.CourseName);

This succeeds

var projection = query.Select(c => new SearchCoursesResult()
        {
            CourseId = c.Id,
            CourseName = c.Name,
            SubjectId = c.Subject.Id,
            SubjectName = c.Subject.Name,
            CourseLevel = c.Level,
            CollegeCourseCode = c.CollegeCourseCode,
            CourseIsActive = c.IsActive
        });
projection.OrderBy(c => c.CourseName);

ninkasi99 avatar Dec 20 '22 18:12 ninkasi99

Linq query OrderBy fails

Fails how? Please provide full exception details (exception message + full stacktrace)

bahusoid avatar Dec 21 '22 11:12 bahusoid

Message: New
Source: NHibernate
Stack Trace:
System.NotSupportedException : New
   at NHibernate.Linq.Visitors.HqlGeneratorExpressionVisitor.VisitExpression(Expression expression)
   at NHibernate.Linq.Visitors.HqlGeneratorExpressionVisitor.VisitMemberExpression(MemberExpression expression)
   at NHibernate.Linq.Visitors.HqlGeneratorExpressionVisitor.VisitExpression(Expression expression)
   at NHibernate.Linq.Visitors.HqlGeneratorExpressionVisitor.Visit(Expression expression, VisitorParameters parameters)
   at NHibernate.Linq.Visitors.QueryModelVisitor.VisitOrderByClause(OrderByClause orderByClause, QueryModel queryModel, Int32 index)
   at Remotion.Linq.Clauses.OrderByClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel, Int32 index)
   at Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection`1 bodyClauses, QueryModel queryModel)
   at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
   at NHibernate.Linq.Visitors.QueryModelVisitor.Visit()
   at NHibernate.Linq.Visitors.QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root, Nullable`1 rootReturnType)
   at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory, Boolean filter)
   at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
   at NHibernate.Engine.Query.QueryExpressionPlan.CreateTranslators(IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
   at NHibernate.Engine.Query.QueryExpressionPlan..ctor(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
   at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)
   at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)
   at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)
   at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query)
   at NHibernate.Linq.DefaultQueryProvider.GetPreparedQuery(Expression expression, NhLinqExpression& nhExpression)
   at NHibernate.Multi.LinqBatchItem.GetForQuery[TResult](IQueryable query, Expression ex)
   at NHibernate.Multi.LinqBatchItem.Create[T](IQueryable`1 query)
   at NHibernate.Multi.QueryBatchExtensions.For[TResult](IQueryable`1 query)
   at NHibernate.Multi.QueryBatchExtensions.AddAsFuture[TResult](IQueryBatch batch, IQueryable`1 query)
   at NHibernate.Linq.LinqExtensionMethods.ToFuture[TSource](IQueryable`1 source)

ninkasi99 avatar Dec 21 '22 15:12 ninkasi99

Hello @bahusoid, did you need more information on this one?

ninkasi99 avatar Jan 02 '23 04:01 ninkasi99

did you need more information on this one?

Nope. Should be enough for someone to work on it.

bahusoid avatar Jan 02 '23 10:01 bahusoid

I think this was not implemented due to constructor being able to have some logic.

The changes would be required in the TransparentIdentifierRemovingExpressionVisitor to teach the specifics of records.

Also, I do not agree that this is a bug. The exception is clearly states that the scenario is not supported.

hazzik avatar Feb 02 '23 03:02 hazzik

Thank you, Alex. I agree that this is not a bug.

ninkasi99 avatar Feb 02 '23 15:02 ninkasi99