[nhusers] Using predicates inside LINQ queries

22 views
Skip to first unread message

ulu

unread,
May 5, 2010, 3:42:00 AM5/5/10
to nhusers
Howdy,

I'm trying to construct a predicate and feed it into a LINQ query. My
Room class has an ISet of Purpose objects, and I'm trying to find
rooms with matching purposes. I started with the following:
Expression<Func<Room, bool>> roomPredicate = r => r.Purposes.Any(p
=> p.Id == 1);
var results = session.Query<Room>().Where(roomPredicate).ToList();
which executes correctly.

But then I refactor the inner predicate into a separate variable (in
order to construct it dynamically later):
Func<Purpose, bool> purposePredicate = p => p.Id == 1;
Expression<Func<Room, bool>> roomPredicate = r =>
r.Purposes.Any(purposePredicate);
var results = session.Query<Room>().Where(roomPredicate).ToList();
it fails with the following exception:
System.ArgumentException: Object of type
'System.Linq.Expressions.ConstantExpression' cannot be converted to
type 'System.Linq.Expressions.LambdaExpression'.

I'm not sure if this is a remotion problem or NH's. In the failing
case, NH provides the following expression to remotion:
value(NHibernate.Linq.NhQueryable`1[Domain.Room]).Where(r =>
r.Purposes.Any(value(System.Func`2[Domain.Purpose,System.Boolean])))

Do you think I should post this to the remotion mailing list?

ulu

Below is the stack trace:

at System.RuntimeType.TryChangeType(Object value, Binder binder,
CultureInfo culture, Boolean needsSpecialCast)
at System.RuntimeType.CheckValue(Object value, Binder binder,
CultureInfo culture, BindingFlags invokeAttr)
at System.Reflection.MethodBase.CheckArguments(Object[] parameters,
Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature
sig)
at
Remotion.Data.Linq.Parsing.Structure.IntermediateModel.MethodCallExpressionNodeFactory.CreateExpressionNode(Type
nodeType, MethodCallExpressionParseInfo parseInfo, Object[]
additionalConstructorParameters)
at
Remotion.Data.Linq.Parsing.Structure.MethodCallExpressionParser.CreateExpressionNode(Type
nodeType, MethodCallExpressionParseInfo parseInfo, Object[]
additionalConstructorParameters)
at
Remotion.Data.Linq.Parsing.Structure.MethodCallExpressionParser.Parse(String
associatedIdentifier, IExpressionNode source, IEnumerable`1 arguments,
MethodCallExpression expressionToParse)
at
Remotion.Data.Linq.Parsing.Structure.ExpressionTreeParser.ParseMethodCallExpression(MethodCallExpression
methodCallExpression, String associatedIdentifier)
at
Remotion.Data.Linq.Parsing.Structure.ExpressionTreeParser.ParseNode(Expression
expression, String associatedIdentifier)
at
Remotion.Data.Linq.Parsing.Structure.ExpressionTreeParser.ParseTree(Expression
expressionTree)
at
Remotion.Data.Linq.Parsing.Structure.QueryParser.GetParsedQuery(Expression
expressionTreeRoot)
at
Remotion.Data.Linq.Parsing.ExpressionTreeVisitors.SubQueryFindingExpressionTreeVisitor.CreateSubQueryNode(MethodCallExpression
methodCallExpression)
at
Remotion.Data.Linq.Parsing.ExpressionTreeVisitors.SubQueryFindingExpressionTreeVisitor.VisitExpression(Expression
expression)
at
Remotion.Data.Linq.Parsing.ExpressionTreeVisitors.SubQueryFindingExpressionTreeVisitor.ReplaceSubQueries(Expression
expressionTree, MethodCallExpressionNodeTypeRegistry nodeTypeRegistry)
at
Remotion.Data.Linq.Parsing.Structure.IntermediateModel.ExpressionResolver.GetResolvedExpression(Expression
unresolvedExpression, ParameterExpression parameterToBeResolved,
ClauseGenerationContext clauseGenerationContext)
at
Remotion.Data.Linq.Parsing.Structure.IntermediateModel.WhereExpressionNode.<>c__DisplayClass1.<GetResolvedPredicate>b__0(ExpressionResolver
r)
at
Remotion.Data.Linq.Parsing.Structure.IntermediateModel.ResolvedExpressionCache`1.GetOrCreate(Func`2
generator)
at
Remotion.Data.Linq.Parsing.Structure.IntermediateModel.WhereExpressionNode.GetResolvedPredicate(ClauseGenerationContext
clauseGenerationContext)
at
Remotion.Data.Linq.Parsing.Structure.IntermediateModel.WhereExpressionNode.ApplyNodeSpecificSemantics(QueryModel
queryModel, ClauseGenerationContext clauseGenerationContext)
at
Remotion.Data.Linq.Parsing.Structure.IntermediateModel.MethodCallExpressionNodeBase.Apply(QueryModel
queryModel, ClauseGenerationContext clauseGenerationContext)
at
Remotion.Data.Linq.Parsing.Structure.QueryParser.ApplyAllNodes(IExpressionNode
node, ClauseGenerationContext clauseGenerationContext)
at
Remotion.Data.Linq.Parsing.Structure.QueryParser.GetParsedQuery(Expression
expressionTreeRoot)
at NHibernate.Linq.NhRelinqQueryParser.Parse(Expression expression)
in f:\Разные штуки\Visual Studio 2008\Projects\OpenSource\NHibernate
\nhibernate\src\NHibernate\Linq\NhRelinqQueryParser.cs:line 58
at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactory
sessionFactory) in f:\Разные штуки\Visual Studio 2008\Projects
\OpenSource\NHibernate\nhibernate\src\NHibernate\Linq
\NhLinqExpression.cs:line 64
at
NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String
queryIdentifier, IQueryExpression queryExpression, String
collectionRole, Boolean shallow, IDictionary`2 filters,
ISessionFactoryImplementor factory) in f:\Разные штуки\Visual Studio
2008\Projects\OpenSource\NHibernate\nhibernate\src\NHibernate\Hql\Ast
\ANTLR\ASTQueryTranslatorFactory.cs:line 27
at
NHibernate.Engine.Query.HQLExpressionQueryPlan.CreateTranslators(String
expressionStr, IQueryExpression queryExpression, String
collectionRole, Boolean shallow, IDictionary`2 enabledFilters,
ISessionFactoryImplementor factory) in f:\Разные штуки\Visual Studio
2008\Projects\OpenSource\NHibernate\nhibernate\src\NHibernate\Engine
\Query\HQLExpressionQueryPlan.cs:line 34
at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String
expressionStr, IQueryExpression queryExpression, String
collectionRole, Boolean shallow, IDictionary`2 enabledFilters,
ISessionFactoryImplementor factory) in f:\Разные штуки\Visual Studio
2008\Projects\OpenSource\NHibernate\nhibernate\src\NHibernate\Engine
\Query\HQLExpressionQueryPlan.cs:line 23
at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String
expressionStr, IQueryExpression queryExpression, Boolean shallow,
IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) in f:
\Разные штуки\Visual Studio 2008\Projects\OpenSource\NHibernate
\nhibernate\src\NHibernate\Engine\Query\HQLExpressionQueryPlan.cs:line
17
at
NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression
queryExpression, Boolean shallow, IDictionary`2 enabledFilters) in f:
\Разные штуки\Visual Studio 2008\Projects\OpenSource\NHibernate
\nhibernate\src\NHibernate\Engine\Query\QueryPlanCache.cs:line 88
at
NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression
queryExpression, Boolean shallow) in f:\Разные штуки\Visual Studio
2008\Projects\OpenSource\NHibernate\nhibernate\src\NHibernate\Impl
\AbstractSessionImpl.cs:line 305
at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression
queryExpression) in f:\Разные штуки\Visual Studio 2008\Projects
\OpenSource\NHibernate\nhibernate\src\NHibernate\Impl
\AbstractSessionImpl.cs:line 261
at NHibernate.Linq.NhQueryProvider.Execute(Expression expression)
in f:\Разные штуки\Visual Studio 2008\Projects\OpenSource\NHibernate
\nhibernate\src\NHibernate\Linq\NhQueryProvider.cs:line 24
at NHibernate.Linq.NhQueryProvider.Execute[TResult](Expression
expression) in f:\Разные штуки\Visual Studio 2008\Projects\OpenSource
\NHibernate\nhibernate\src\NHibernate\Linq\NhQueryProvider.cs:line 55
at Remotion.Data.Linq.QueryableBase`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1
collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at ZTests.PredicateTest.CanUseAPredicateInLinqQueries() in F:
\Разные штуки\Visual Studio 2008\Projects\RentASpace\ZTests
\PredicateTest.cs:line 30

--
You received this message because you are subscribed to the Google Groups "nhusers" group.
To post to this group, send email to nhu...@googlegroups.com.
To unsubscribe from this group, send email to nhusers+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nhusers?hl=en.

Stefan Wenig

unread,
May 6, 2010, 5:01:35 AM5/6/10
to nhusers, fabian....@rubicon.eu
Hi

In your case, the problem is neither NH's nor re-linq's, but the
Func<...> purposePredicate you're inserting into your query. This is
compiled code, not an IQueryable AST that can be converted to HQL.
Inside the IQueryable, it's a constant expression, and that's just
what the exception message says. (That said, it could be more specific
about the source of the problem.)

purposePredicate would need to be an Expression<...> too, but to get a
matching overload of any, Purposes would need to be of type
IQueryable<Purpose>.

You could try some subquery construct, or this should solve your
problem:
Expression<Func<Purpose, bool>> purposePredicate = p2 => p2.Id
== 1;
Expression<Func<Room, bool>> roomPredicate2 = r =>
r.Purposes.ToQueryable().Any(purposePredicate);

The ToQueryable method would be easy to build (casting explicitly
would be ugly), but re-linq would need to be aware of it (and probably
just ignore it).

Now if you want that, that would be a good time to switch to our list.

HTH,
Stefan

http://relinq.codeplex.com/
> Remotion.Data.Linq.Parsing.Structure.IntermediateModel.MethodCallExpression­NodeFactory.CreateExpressionNode(Type
> nodeType, MethodCallExpressionParseInfo parseInfo, Object[]
> additionalConstructorParameters)
>    at
> Remotion.Data.Linq.Parsing.Structure.MethodCallExpressionParser.CreateExpre­ssionNode(Type
> nodeType, MethodCallExpressionParseInfo parseInfo, Object[]
> additionalConstructorParameters)
>    at
> Remotion.Data.Linq.Parsing.Structure.MethodCallExpressionParser.Parse(Strin­g
> associatedIdentifier, IExpressionNode source, IEnumerable`1 arguments,
> MethodCallExpression expressionToParse)
>    at
> Remotion.Data.Linq.Parsing.Structure.ExpressionTreeParser.ParseMethodCallEx­pression(MethodCallExpression
> methodCallExpression, String associatedIdentifier)
>    at
> Remotion.Data.Linq.Parsing.Structure.ExpressionTreeParser.ParseNode(Express­ion
> expression, String associatedIdentifier)
>    at
> Remotion.Data.Linq.Parsing.Structure.ExpressionTreeParser.ParseTree(Express­ion
> expressionTree)
>    at
> Remotion.Data.Linq.Parsing.Structure.QueryParser.GetParsedQuery(Expression
> expressionTreeRoot)
>    at
> Remotion.Data.Linq.Parsing.ExpressionTreeVisitors.SubQueryFindingExpression­TreeVisitor.CreateSubQueryNode(MethodCallExpression
> methodCallExpression)
>    at
> Remotion.Data.Linq.Parsing.ExpressionTreeVisitors.SubQueryFindingExpression­TreeVisitor.VisitExpression(Expression
> expression)
>    at
> Remotion.Data.Linq.Parsing.ExpressionTreeVisitors.SubQueryFindingExpression­TreeVisitor.ReplaceSubQueries(Expression
> expressionTree, MethodCallExpressionNodeTypeRegistry nodeTypeRegistry)
>    at
> Remotion.Data.Linq.Parsing.Structure.IntermediateModel.ExpressionResolver.G­etResolvedExpression(Expression
> unresolvedExpression, ParameterExpression parameterToBeResolved,
> ClauseGenerationContext clauseGenerationContext)
>    at
> Remotion.Data.Linq.Parsing.Structure.IntermediateModel.WhereExpressionNode.­<>c__DisplayClass1.<GetResolvedPredicate>b__0(ExpressionResolver
> r)
>    at
> Remotion.Data.Linq.Parsing.Structure.IntermediateModel.ResolvedExpressionCa­che`1.GetOrCreate(Func`2
> generator)
>    at
> Remotion.Data.Linq.Parsing.Structure.IntermediateModel.WhereExpressionNode.­GetResolvedPredicate(ClauseGenerationContext
> clauseGenerationContext)
>    at
> Remotion.Data.Linq.Parsing.Structure.IntermediateModel.WhereExpressionNode.­ApplyNodeSpecificSemantics(QueryModel
> queryModel, ClauseGenerationContext clauseGenerationContext)
>    at
> Remotion.Data.Linq.Parsing.Structure.IntermediateModel.MethodCallExpression­NodeBase.Apply(QueryModel
> queryModel, ClauseGenerationContext clauseGenerationContext)
>    at
> Remotion.Data.Linq.Parsing.Structure.QueryParser.ApplyAllNodes(IExpressionN­ode
> node, ClauseGenerationContext clauseGenerationContext)
>    at
> Remotion.Data.Linq.Parsing.Structure.QueryParser.GetParsedQuery(Expression
> expressionTreeRoot)
>    at NHibernate.Linq.NhRelinqQueryParser.Parse(Expression expression)
> in f:\Разные штуки\Visual Studio 2008\Projects\OpenSource\NHibernate
> \nhibernate\src\NHibernate\Linq\NhRelinqQueryParser.cs:line 58
>    at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactory
> sessionFactory) in f:\Разные штуки\Visual Studio 2008\Projects
> \OpenSource\NHibernate\nhibernate\src\NHibernate\Linq
> \NhLinqExpression.cs:line 64
>    at
> NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(S­tring
Reply all
Reply to author
Forward
0 new messages