Skip to content

NH-3005 - NHibernate.Hql.Ast.HqlIdent..ctor throws Don't currently support idents of type Date #1264

Closed
@nhibernate-bot

Description

@nhibernate-bot

kkozmic created an issue — 10th January 2012, 1:24:03:

So I have a custom IUserType for class called Date which represents a date and maps to a date type in SQL Server.

I then have a query:


var query = from link in Session.Query<InvoiceExportInvoice>()
			let export = link.InvoiceExport
			let invoice = link.Invoice
			let creditNote = invoice.CreditNote
			select new
			{
				ExportId = export.Id,
				Date = (link.IsCredited ? creditNote.CreditedDate : invoice.InvoicedDate),
				Number = (link.IsCredited ? creditNote.CreditNoteNumber : invoice.InvoiceNumber),
			};

query.ToList();

both CreditNote.Date and Invoice.InvoicedDate are of the custom type Date mapped via IUserType to date in the database.

When I try to run this query the following exception gets thrown:

System.NotSupportedException: Don't currently support idents of type Date
at NHibernate.Hql.Ast.HqlIdent..ctor(IASTFactory factory, Type type)
at NHibernate.Hql.Ast.HqlCast..ctor(IASTFactory factory, HqlExpression expression, Type type)
at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitConditionalExpression(ConditionalExpression expression)
at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitExpression(Expression expression)
at NHibernate.Linq.Visitors.SelectClauseVisitor.VisitExpression(Expression expression)
at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitAndConvert(T expression, String methodName)
at Remotion.Linq.Parsing.ExpressionTreeVisitor.<>c*_DisplayClass61.<VisitAndConvert>b_*5(T expression) at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList(ReadOnlyCollection1 list, Func2 visitMethod) at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitAndConvert(ReadOnlyCollection1 expressions, String callerName)
at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitNewExpression(NewExpression expression)
at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression)
at NHibernate.Linq.Visitors.SelectClauseVisitor.VisitExpression(Expression expression)
at NHibernate.Linq.Visitors.SelectClauseVisitor.Visit(Expression expression)
at NHibernate.Linq.Visitors.QueryModelVisitor.VisitSelectClause(SelectClause selectClause, QueryModel queryModel)
at Remotion.Linq.Clauses.SelectClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel)
at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
at NHibernate.Linq.Visitors.QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root)
at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory)
at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String queryIdentifier, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary2 filters, ISessionFactoryImplementor factory) at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary2 enabledFilters)
at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)
at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)
at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, ref IQuery query, ref NhLinqExpression nhQuery)
at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
at Remotion.Linq.QueryableBase1.GetEnumerator() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList(IEnumerable1 source)

I see no reason why that shouldn't work for my custom Date type. It does work if the properties are of DateTime type...


Oskar Berggren added a comment — 16th December 2012, 18:34:05:

What happens is that HqlGeneratorExpressionTreeVisitor likes to generate HQL casts to wrap the HQL generated for some expressions. I'm not entirely sure why. Anyway, the generate the cast it must generate some string name for the intended type, based on the System.Type of the linq expression. This is what is done in HqlIdent, which only supports some common .Net types. HQL will later translate that type name into the corresponding sql type, which may vary by dialect.

It's not obvious how it should handle IUserTypes. When the LINQ expression is being parsed, we only see the Date type, not it's corresponding IUserType. Conceivably, we could put the class' full name or assembly qualified name in the HQL. Then the HQL engine needs a mapping from e.g. "MyModel.Date, MyModel" to an instance of "MyPersistance.DateUserType", where it can get the corresponding SQL type. But I don't think such a mapping exists currently.

As a side note, if we do e.g. someQuery.Min(m => m.PointInTime) where PointInTime is DateTime but mapped using the built-in DateTime2, the query will generate a cast to SQL DATETIME and thus lose the precision of DATETIME2.

I wonder if we can remove some of these implicitly generated casts to mitigate the problem...

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions