我有一些代码生成表达式作为数据库读取中的“where”语句传递,我正在尝试加快速度。
下面的示例使用 where 语句将表的 PK 与传入的值匹配:
private Expression MakeWhereForPK(int id)
{
var paramExp = Expression.Parameter(typeof(Brand),"b");
//Expression to get value from the entity
var leftExp = Expression.Property(paramExp,"ID");
//Expression to state the value to match (from the passed in variable)
var rightExp = Expression.Constant(id,typeof(int));
//Expression to compare the two
var whereExp = Expression.Equal(leftExp,rightExp);
return Expression.Lambda<Func<Brand,bool>>(whereExp,paramExp);
}
以上是对问题的简化 - 真实的内容包括获取表以查询并找到其 PK 等的代码。它实际上与您通常在代码中可能执行的操作相同:
ctx.Brands.Where(b => b.ID = id);
这工作正常,但是,在进行测试以优化事物时,我发现它相当慢 - 执行上述 1000000 次大约需要 25 秒。如果我省略上面的最后一行会更好(但显然它没有用!),所以它似乎是 Expression.Lamba 花费了大约 2/3 的时间,但其余的也不是很好。
如果所有查询都将同时发生,我可以将其转换为IN
样式表达式并生成一次,但不幸的是这是不可能的,所以我希望保存上面的大部分生成,并重用生成的表达式,但传入不同的值id
。
请注意,由于这将被传递给 Linq,因此我无法将表达式编译为具有可以在调用时传递的整数参数 - 它必须保留为表达式树。
因此,出于进行计时练习的目的,以下可能是一个简单的版本:
Expression<Func<Brand,bool>> savedExp;
private Expression MakeWhereForPKWithCache(int id)
{
if (savedExp == null)
{
savedExp = MakeWhereForPK(id);
}
else
{
var body = (BinaryExpression)savedExp.Body;
var rightExp = (ConstantExpression)body.Right;
//At this point, value is readonly, so is there some otherway to "inject" id,
//and save on compilation?
rightExp.Value = id;
}
return savedExp;
}
我如何重新使用表达式,只是使用不同的 id 值?