Reputation: 3171
It looks like each time I query something with LINQ NHibernate builds that query from scratch:
The code looks like
session.Query<User>().Where(x => ids.Contains(x.Id)).ToFuture();
Is it possible to avoid recompiling it?
Also the same question about caching QueryOver/Criteria queries (not so critical but it may still fit the scope).
Upvotes: 2
Views: 216
Reputation: 119
I recall that expressions with the contains linq method are not compiled because the enumerable could be different in future calls
A possible workaround is to use the ugly way of OR operator if you know that the number of elements is always the same
Another workaround is to call the following method:
session.QueryOver().AndRestrictionOn(x=>x.id).IsIn(ids)
Upvotes: 1
Reputation: 3171
Particularly this case was caused by that the access to ids (int[]
) here
session.Query<User>().Where(x => ids.Contains(x.Id)).ToFuture();
was transformed into MemberAccessExpression
(not ConstantExpression
) and NHibernate had to evaluate it. Though ids
was never changed it still was captured into a closure generated class (like DisplayClass<>.ids
).
I optimized this case by making my own version of PartialEvaluatingExpressionTreeVisitor
:
protected Expression EvaluateSubtree(Expression subtree)
{
ArgumentUtility.CheckNotNull(nameof(subtree), subtree);
var memberExpression = subtree as MemberExpression;
if (memberExpression != null)
{
Expression constant;
if (TryEvaluateMember(memberExpression, out constant)) return constant;
}
if (subtree.NodeType != ExpressionType.Constant)
throw new NHibernateExpressionOptimizerException(subtree);
ConstantExpression constantExpression = (ConstantExpression)subtree;
IQueryable queryable = constantExpression.Value as IQueryable;
if (queryable != null && queryable.Expression != constantExpression)
return queryable.Expression;
return constantExpression;
}
bool TryEvaluateMember(MemberExpression memberExpression, out Expression constant)
{
constant = null;
ConstantExpression c = memberExpression.Expression == null ? Expression.Constant(null) : EvaluateSubtree(memberExpression.Expression) as ConstantExpression;
if (c == null) return false;
var fieldInfo = memberExpression.Member as FieldInfo;
if (fieldInfo != null)
{
constant = Expression.Constant(ReflectorReadFieldDelegate(fieldInfo, c.Value));
return true;
}
var propertyInfo = memberExpression.Member as PropertyInfo;
if (propertyInfo != null)
{
constant = Expression.Constant(ReflectorReadPropertyDelegate(propertyInfo, c.Value));
return true;
}
return false;
}
The reflector delegates use a kind of cached reflection.emit magic.
Upvotes: 0