Cannot write Linq query with an entity mapped with a property accessor

Description

I have a "MenuOption" entity which declares a property "Enabled" of type boolean. It uses a legacy database which stores the boolean as text, so I use a property accessor to convert from char to boolean and vice versa.

If I write an HQL query or use the criteria API, the property accessor is not used, so I have to put the string value I want to match (the text "true", not the boolean 'true'):
var menuOptions = session.CreateCriteria<MenuOption>()
.Add(Expression.Eq("Enabled", "True")) // string, not boolean
.List<MenuOption>();

With the Linq syntax, I cannot write "True" because the type is not of type boolean:
var menuOptions = from o in context.MenuOptions
where o.Enabled == "True" // won't compile
select o;

I can try using the boolean:
var menuOptions = from o in context.MenuOptions
where o.Enabled == true // will fail at runtime
select o;

But then I get a QueryException:

NHibernate.QueryException was unhandled
Message="Type mismatch in NHibernate.Criterion.SimpleExpression: Enabled expected type System.String, actual type System.Boolean"
Source="NHibernate"
StackTrace:
à NHibernate.Criterion.CriterionUtil.GetColumnNamesUsingPropertyName(ICriteriaQuery criteriaQuery, ICriteria criteria, String propertyName, Object value, ICriterion critertion)
à NHibernate.Criterion.CriterionUtil.GetColumnNamesForSimpleExpression(String propertyName, IProjection projection, ICriteriaQuery criteriaQuery, ICriteria criteria, IDictionary`2 enabledFilters, ICriterion criterion, Object value)
à NHibernate.Criterion.SimpleExpression.ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery, IDictionary`2 enabledFilters)
à NHibernate.Loader.Criteria.CriteriaQueryTranslator.GetWhereCondition(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()
à NHibernate.Impl.CriteriaImpl.UniqueResult()
à NHibernate.Linq.Visitors.ImmediateResultsVisitor`1.HandleAggregateCall(MethodCallExpression call)
à NHibernate.Linq.Visitors.ImmediateResultsVisitor`1.VisitMethodCall(MethodCallExpression call)
à NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression exp)
à NHibernate.Linq.Visitors.NHibernateExpressionVisitor.Visit(Expression exp)
à NHibernate.Linq.Visitors.ImmediateResultsVisitor`1.GetResults(MethodCallExpression expr)
à NHibernate.Linq.Visitors.RootVisitor.HandleImmediateResultsCall(MethodCallExpression call)
à NHibernate.Linq.Visitors.RootVisitor.VisitMethodCall(MethodCallExpression expr)
à NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression exp)
à NHibernate.Linq.Visitors.NHibernateExpressionVisitor.Visit(Expression exp)
à NHibernate.Linq.Visitors.NHibernateQueryTranslator.Translate(Expression expression, QueryOptions queryOptions)
à NHibernate.Linq.NHibernateQueryProvider.TranslateExpression(Expression expression)
à NHibernate.Linq.NHibernateQueryProvider.Execute(Expression expression)
à NHibernate.Linq.QueryProvider.System.Linq.IQueryProvider.Execute[T](Expression expression)
à System.Linq.Queryable.Count[TSource](IQueryable`1 source)
à NHibernateLinqSample.Program.Main(String[] args) dans D:\Temp\NHibernateLinqSample\NHibernateLinqSample\Program.cs:ligne 48
à System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
à System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
à Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
à System.Threading.ThreadHelper.ThreadStart_Context(Object state)
à System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
à System.Threading.ThreadHelper.ThreadStart()
InnerException:

Attached is a sample console application which reproduces the issue. To make it work, you need to fix the library references (I could not add them to the zip file to make it fit).

Environment

None

Attachments

1

Activity

Show:

Richard Gavel 
May 17, 2010 at 2:19 PM

It sounds like you're using a non-optimal way of doing this in the first place. You shouldn't be putting knowledge of the transform mapping in your query in the first place. You can provide NHibernate with a mapper class that will auto translate text to boolean and vice-versa. Then your code will refer to it always as a boolean. The post below explains this:

http://www.lostechies.com/blogs/rhouston/archive/2008/03/23/mapping-strings-to-booleans-using-nhibernate-s-iusertype.aspx

Details

Assignee

Reporter

Components

Affects versions

Priority

Who's Looking?

Open Who's Looking?
Created August 20, 2009 at 5:20 AM
Updated May 17, 2010 at 2:19 PM
Who's Looking?