如何缓存已编译的LINQ查询(不是结果)?

时间:2017-08-07 21:16:11

标签: c# performance linq nhibernate expression-trees

看起来每次我使用LINQ NHibernate查询内容从头开始构建查询:

dotTrace report

代码看起来像

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

是否可以避免重新编译?

同样关于缓存QueryOver / Criteria查询的问题(不是那么关键,但它可能仍然符合范围)。

2 个答案:

答案 0 :(得分:1)

我还记得没有编译带有contains linq方法的表达式,因为在以后的调用中可枚举可能会有所不同

一种可能的解决方法是,如果您知道元素数始终相同,则使用OR运算符的丑陋方式

另一种解决方法是调用以下方法:

session.QueryOver()。AndRestrictionOn(x => x.id).IsIn(ids)

答案 1 :(得分:0)

特别是这种情况是由于访问ID(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;
    }

反射器委托使用一种缓存的反射.emit magic。