2017-08-07 61 views
1

它看起来每个I查询一些与LINQ NHibernate的时间一样从头开始构建该查询:如何缓存编译的LINQ查询(不是结果)?

dotTrace report

代码看起来像

session.Query<User>().Where(x => ids.Contains(x.Id)).ToFuture(); 

是否有可能避免重新编译呢?

关于缓存QueryOver/Criteria查询的相同问题(不是很重要,但它可能仍然适合范围)。

+0

@stybl“重用LINQ查询”和“重用LINQ到数据库NH查询”是不一样的东西 – Vlad

+0

我知道,这就是为什么我撤回了近距离投票。虽然忘记了评论。 – stybl

+1

https://stackoverflow.com/a/4817010/1162077 –

回答

0

特别是这种情况下被接入到IDS(int[])造成这里

session.Query<User>().Where(x => ids.Contains(x.Id)).ToFuture(); 

转化MemberAccessExpression(不ConstantExpression)和NHibernate不得不对其进行评估。尽管ids从未被更改过,但它仍被捕获到一个关闭生成的类中(如DisplayClass<>.ids)。

我通过制作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; 
    } 

反射器代表使用一种缓存Reflection.Emit的魔力。

+0

这听起来像改变了我一般不喜欢的默认行为。为什么不把它包装在一个方法调用中,如公共静态T ToConst (T item){return item;},然后将该逻辑用于该方法调用?它给你更多的灵活性,更清楚你的意图是什么,不是吗? – MBoros