1
嘿,所有。我试图通过静态缓存和重新使用已编译的查询来优化Linq to Entities调用。查询为可变数目的过滤器参数检查同样的事情,编译查询参数的唯一方法就是显式使用一些参数(而不是一些Contains() - 类型逻辑,它们在SQL中不能参数)。如何分解参数化表达式中的子句?
这很好,给了我一个重大的性能提升。问题是代码是丑陋的。对于每个可能的参数,我重复相同的代码块数次。即:
Expression<Func<Entities, string, string, string, string, IQueryable<Instrument>>> query =
(context, searchTerm0, searchTerm1, searchTerm2, searchTerm3) =>
context.Instruments
.Where(
(searchTerm0 == null ||
instr.FullName.IndexOf(searchTerm0) > -1 ||
instr.ShortName.IndexOf(searchTerm0) > -1 ||
instr.Strategies.OrderBy(st => st.Level).Select(st => st.Name).Take(2).Any(strat => strat.IndexOf(searchTerm0) > -1))
&&
(searchTerm1 == null ||
instr.FullName.IndexOf(searchTerm1) > -1 ||
instr.ShortName.IndexOf(searchTerm1) > -1 ||
instr.Strategies.OrderBy(st => st.Level).Select(st => st.Name).Take(2).Any(strat => strat.IndexOf(searchTerm1) > -1))
&&
(searchTerm2 == null ||
instr.FullName.IndexOf(searchTerm2) > -1 ||
instr.ShortName.IndexOf(searchTerm2) > -1 ||
instr.Strategies.OrderBy(st => st.Level).Select(st => st.Name).Take(2).Any(strat => strat.IndexOf(searchTerm2) > -1))
&&
(searchTerm3 == null ||
instr.FullName.IndexOf(searchTerm3) > -1 ||
instr.ShortName.IndexOf(searchTerm3) > -1 ||
instr.Strategies.OrderBy(st => st.Level).Select(st => st.Name).Take(2).Any(strat => strat.IndexOf(searchTerm3) > -1))
.Take(50);
我想我可以通过动态创建过滤器表达式来重构这个,但这似乎是不可能的。我想要做这样的事情:
var filterExpression = (instr, searchTerm) =>
searchTerm == null ||
instr.FullName.IndexOf(searchTerm) > -1 ||
instr.ShortName.IndexOf(searchTerm) > -1 ||
instr.Strategies.OrderBy(st => st.Level).Select(st => st.Name).Take(2).Any(strat => strat.IndexOf(searchTerm) > -1);
Expression<Func<Entities, string, string, string, string, IQueryable<Instrument>>> query = (context, searchTerm0, searchTerm1, searchTerm2, searchTerm3) =>
context.Instruments
.Where(i => filterExpression(i, searchTerm0))
.Where(i => filterExpression(i, searchTerm1))
.Where(i => filterExpression(i, searchTerm2))
.Where(i => filterExpression(i, searchTerm3))
.Take(50);
当然,这不能编译,因为filterExpression是一个表达式,不能叫成这样(和它不能只是一个Func键,因为LINQ到的,但实体不会将其识别为可翻译的方法)。
我也无法捕获表达式外的闭包中的参数,因为如果我重新使用编译的表达式,最后一次调用的值将被硬编码并重新使用。即,这不是一个参数化查询。
我为每个学期写出了全部内容吗?我想最多支持14个。是否可以将这些带参数的子句分解出来?
不确定Predicate Builder如何帮助我。我想要做的是创建一个表达式并编译一次,然后用不同的参数重新使用它。除非我错过了某些东西,否则Predicate Builder示例使用闭包中捕获的过滤器值,即它们不是表达式的参数,将在随后使用编译后的查询时重新使用。我明白这是正确的吗? – dks1983 2011-04-29 14:45:44
啊......我明白你在找什么。你是正确的,Predicate Builder不会为你做到这一点。但是,我不认为你可以在LINQ to EF中执行编译的方法。实质上,所有谓词都转换为T-SQL。编译后的查询无法由LINQ转换为EF提供程序,并且最终你最终会使用Predicate Builder。 – 2011-04-29 18:28:58
是的,我在顶端的工作方式 - 我可以编译竞争表达式,并用不同的参数成功重用它 - 但最终我不得不写出所有该死的东西来支持多达十几个参数。 – dks1983 2011-04-29 22:16:04