如何重用Linq To Sql查询中的where子句

Xav*_*nas 14 .net c# linq-to-sql

我有用户搜索记录类型的记录.他们在文本框中键入搜索词,然后通过将多个字段与搜索词匹配来搜索记录.

我的查询如下:

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;
Run Code Online (Sandbox Code Playgroud)

我有许多查询都使用相同的过滤器,因此我想提取过滤,以便可以重复使用.就像是:

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;
Run Code Online (Sandbox Code Playgroud)

但是,它不起作用,因为:

方法'System.Object DynamicInvoke(System.Object [])'没有支持的SQL转换.

如何跨查询重用where where条件?

ito*_*son 14

您需要构建表达式而不是函数:

Expression<Func<Record, bool>> filter = 
  record => record.Field1.ToLower().Contains(term);  // rest omitted
Run Code Online (Sandbox Code Playgroud)

lambda表达式保持不变,但您需要将其返回到类型变量中Expression<Func<Record, bool>>- 这将使C#编译器将其编译为表达式而不是委托,从而允许将其传递给LINQ to SQL.

但是,您将无法将表达式变量与C#-syntax where子句一起使用:您需要使用Where扩展方法:

var results = DataContext.Records.Where(filter);
Run Code Online (Sandbox Code Playgroud)

编辑添加:如果您希望能够在不同的条件上创建过滤器,您只需要一个方法来从术语生成表达式:

private static Expression<Func<Record, bool>> Filter(string term)
{
  return r => r.Field1.ToLower().Contains(term);
}

var results = DataContext.Records.Where(Filter(term));
Run Code Online (Sandbox Code Playgroud)

如果你喜欢filter像现在一样保持lambda,你可以这样做,但是泛型有点嵌套:

Func<string, Expression<Func<Record, bool>>> filter =
  term => (r => r.Field1.ToLower().Contains(term));

var results = DataContext.Records.Where(filter(term));
Run Code Online (Sandbox Code Playgroud)

无论如何,重要的是Where子句中的内容必须是Expression<Func<Record, bool>>- 但如上所示,您可以term通过动态构建合适的表达式来使表达式依赖.如果你在Where子句中详细说明过滤器,这正是LINQ to SQL所要做的.

  • 虽然我选择了`CompiledQuery`,但这种方法的优点是不将表达式绑定到`DataContext`.无论如何,我从中学到了很多东西! (2认同)

Jef*_*ado 12

使用CompiledQuery!

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;
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参见如何:存储和重用查询.