Skip to content

NH-3847 - ConditionalProjection throws "Both true and false projections must return the same types" when the types are the same #1180

Closed
@nhibernate-bot

Description

@nhibernate-bot

Alan Carroll created an issue — 18th February 2016, 15:50:29:

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))));

{noformat:title=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]


{noformat:title=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

Alan Carroll added a comment — 14th June 2017, 16:54:36:

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

TypeFactory.GetAnsiStringType(200)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions