ConditionalProjection throws "Both true and false projections must return the same types" when the types are the same

Description

The code below generates the exception shown. Client, company, and vendor name are all AnsiString type, with a length of 200. The problem stems from the type equality comparison, which uses the string length. NHibernateUtil.AnsiString does not have a length defined. Perhaps exact type equality is not what we want here.

var associate = Projections.Conditional( Restrictions.IsNotNull(Projections.Property(() => this.root.Client)), Projections.Property(() => this.client.Name), Projections.Conditional( Restrictions.IsNotNull(Projections.Property(() => this.root.Company)), Projections.Property(() => this.company.Name), Projections.Conditional( Restrictions.IsNotNull(Projections.Property(() => this.root.Vendor)), Projections.Property(() => this.vendor.Name), Projections.Constant(null, NHibernateUtil.AnsiString))));

Exception

Both true and false projections must return the same types. But True projection returns: [NHibernate.Type.AnsiStringType] And False projection returns: [NHibernate.Type.AnsiStringType]

Stack Trace

[HibernateException: Both true and false projections must return the same types. But True projection returns: [NHibernate.Type.AnsiStringType] And False projection returns: [NHibernate.Type.AnsiStringType]] NHibernate.Criterion.ConditionalProjection.GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery) NHibernate.Criterion.SimpleProjection.GetColumnCount(ICriteria criteria, ICriteriaQuery criteriaQuery) NHibernate.Criterion.SimpleProjection.GetColumnAliases(Int32 position, ICriteria criteria, ICriteriaQuery criteriaQuery) NHibernate.Criterion.ConditionalProjection.ToSqlString(ICriteria criteria, Int32 position, ICriteriaQuery criteriaQuery, IDictionary`2 enabledFilters) NHibernate.Criterion.ConditionalProjection.ToSqlString(ICriteria criteria, Int32 position, ICriteriaQuery criteriaQuery, IDictionary`2 enabledFilters) NHibernate.Criterion.ConditionalProjection.ToSqlString(ICriteria criteria, Int32 position, ICriteriaQuery criteriaQuery, IDictionary`2 enabledFilters) NHibernate.Criterion.AliasedProjection.ToSqlString(ICriteria criteria, Int32 position, ICriteriaQuery criteriaQuery, IDictionary`2 enabledFilters) NHibernate.Criterion.ProjectionList.ToSqlString(ICriteria criteria, Int32 loc, ICriteriaQuery criteriaQuery, IDictionary`2 enabledFilters) NHibernate.Loader.Criteria.CriteriaQueryTranslator.GetSelect(IDictionary`2 enabledFilters) NHibernate.Loader.Criteria.CriteriaJoinWalker..ctor(IOuterJoinLoadable persister, CriteriaQueryTranslator translator, ISessionFactoryImplementor factory, ICriteria criteria, String rootEntityName, IDictionary`2 enabledFilters) NHibernate.Loader.Criteria.CriteriaLoader..ctor(IOuterJoinLoadable persister, ISessionFactoryImplementor factory, CriteriaImpl rootCriteria, String rootEntityName, IDictionary`2 enabledFilters) NHibernate.Impl.SessionImpl.List(CriteriaImpl criteria, IList results) NHibernate.Impl.CriteriaImpl.List(IList results) NHibernate.Impl.CriteriaImpl.List[T]() NHibernate.Criterion.QueryOver`1.List[U]() NHibernate.Criterion.QueryOver`1.NHibernate.IQueryOver<TRoot>.List[U]()

Since AnsiStringType does not have a public constructor, we cannot create our own with a matching length. My temporary workaround is to create my own class that inherits from AbstractStringType, and specify the length.

private class MyAnsiStringType : NHibernate.Type.AbstractStringType { public MyAnsiStringType() : base (new NHibernate.SqlTypes.AnsiStringSqlType(200)) { } public override string Name { get { return "AnsiString"; } } }

This works, since the lengths are all the same, but I should be able to do a conditional that returns strings of varying lengths. Furthermore, I should be able to return any string type, because this is valid SQL (SQL Server at least).

select case when 1 = 1 then '1' when 1 = 2 then N'2' end

Environment

None

Activity

Alex Zaytsev 
September 14, 2020 at 11:04 PM

Moved here.

Alan Carroll 
June 14, 2017 at 4:54 PM

I've found a simpler way to work around this issue using the built-in NHibernate.Type.TypeFactory.

TypeFactory.GetAnsiStringType(200)
Fixed

Details

Assignee

Reporter

Components

Fix versions

Affects versions

Priority

Who's Looking?

Open Who's Looking?
Created February 18, 2016 at 3:50 PM
Updated September 14, 2020 at 11:04 PM
Resolved September 14, 2020 at 11:04 PM
Who's Looking?