我让用户搜索Record类型的记录。他们在文本框中键入搜索词,然后通过将多个字段与搜索词匹配来搜索记录。
我的查询如下:
var results = from record in DataContext.Records
where
record.Field1.ToLower().Contains(term) ||
record.Field2.ToLower().Contains(term) ||
record.Field3.ToLower().Contains(term)
select record;
我有许多查询都使用相同的过滤器,因此我想提取过滤,以便可以重复使用。类似的东西:
var filter = new Func<Record, string, bool>(
(record, term) =>
record.Field1.ToLower().Contains(term) ||
record.Field2.ToLower().Contains(term) ||
record.Field3.ToLower().Contains(term)
);
var results = from record in DataContext.Records
where filter(record, term)
select record;
但是,它不起作用,因为:
方法'System.Object DynamicInvoke(System.Object [])'没有支持的SQL转换。
如何跨查询重用where where条件?
答案 0 :(得分:13)
您需要构建表达式而不是函数:
Expression<Func<Record, bool>> filter =
record => record.Field1.ToLower().Contains(term); // rest omitted
lambda表达式保持不变,但您需要将其返回到Expression<Func<Record, bool>>
类型的变量中 - 这将使C#编译器将其编译为表达式而不是委托,允许将其传递给LINQ to SQL。
但是,您将无法将表达式变量与C#-syntax where子句一起使用:您需要使用Where扩展方法:
var results = DataContext.Records.Where(filter);
编辑添加:如果您希望能够在不同的条件下创建过滤器,则只需要一种方法从术语生成表达式:
private static Expression<Func<Record, bool>> Filter(string term)
{
return r => r.Field1.ToLower().Contains(term);
}
var results = DataContext.Records.Where(Filter(term));
如果您希望将filter
保留为目前的lambda,则可以这样做,但是泛型有点嵌套:
Func<string, Expression<Func<Record, bool>>> filter =
term => (r => r.Field1.ToLower().Contains(term));
var results = DataContext.Records.Where(filter(term));
无论如何,重要的是Where子句中的内容必须是Expression<Func<Record, bool>>
- 但如上所示,您可以通过动态构建合适的表达式使表达式依赖于term
。如果你在Where子句中详细说明过滤器,这正是LINQ to SQL所做的。
答案 1 :(得分:13)
var filter = CompiledQuery.Compile(
(DatabaseDataContext dc, Record record, string term) =>
record.Field1.ToLower().Contains(term) ||
record.Field2.ToLower().Contains(term) ||
record.Field3.ToLower().Contains(term)
);
var results = from record in DataContext.Records
where filter(DataContext, record, term)
select record;
有关详细信息,请参阅How to: Store and Reuse Queries。
答案 2 :(得分:3)
除了其他人指出的Expression<Func<Record, bool>>
问题外,我建议调查PredicateBuilder。这对于动态组合lambda表达式非常有用。
答案 3 :(得分:1)
我认为您需要将其设为Expression<Func<Record, bool>>
。否则,它试图将实际的C#方法调用转换为SQL而不是它的描述。这并不能保证此版本能够正常运行;我不确定哪些字符串函数可以转换为SQL。