如何将 Predicate<T> 传递给 Linq to SQL 中的 Where() 方法?

Posted

技术标签:

【中文标题】如何将 Predicate<T> 传递给 Linq to SQL 中的 Where() 方法?【英文标题】:How can I pass a Predicate<T> to the Where() method in Linq to SQL? 【发布时间】:2010-11-11 16:41:29 【问题描述】:

我有以下型号:

 +--------+
 | Folder |
 +--------+
     | 1
     |
     | *
+----------+         +---------+
| WorkItem |---------| Project |
+----------+ *     1 +---------+

我需要检索具有当前 WorkItems 计数的文件夹列表。

如果我指定了一个项目,那么我只需要每个文件夹中与指定项目关联的工作项的计数。

如果没有指定 Project,它应该返回 WorkItem 总数。

我有以下 Linq to SQL 代码:

public interface IWorkItemCriteria 
    int? ProjectId  get; 


public static IQueryable<Folder> GetFoldersWithItemCounts(IWorkItemCriteria criteria) 
    var results = from folder in dataContext.Folders
        select new 
              Folder = folder,
              Count = folder.WorkItems.Count()
    ;
    return(results);

问题是 - 我想过滤正在计数的工作项。

这行得通:

    var results = from folder in dataContext.Folders
        select new 
              Folder = folder,
              Count = folder.WorkItems.Where(item => item.ProjectId == criteria.ProjectId).Count()
    ;

但我无法让它使用任何类型的动态谓词/表达式。我尝试使用的语法是:

    var results = from folder in dataContext.Folders
        select new 
              Folder = folder,
              Count = folder.WorkItems.Where(filter).Count()
    ;

我试过了

Predicate<WorkItem> filter = (item => item.ProjectId == criteria.ProjectId);

Expression<Func<WorkItem, bool>> filter = (item => item.ProjectId == criteria.ProjectId)

两者都不会编译 - 给出The type arguments for method 'System.Linq.Enumerable.Where&lt;TSource&gt; (System.Collections.Generic.IEnumerable&lt;TSource&gt;, System.Func&lt;TSource,bool&gt;)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

我试过了

Func<WorkItem, bool> filter = (item => item.ProjectId == criteria.ProjectId);

构建,但随后因“用于查询运算符 'Where' 的不支持重载而失败。”

我将需要向 IWorkItemCriteria 接口添加额外的属性,因此动态构造可以被 Linq 干净地转换为 SQL 的谓词的能力非常重要。

有什么想法吗?

【问题讨论】:

【参考方案1】:

我认为您的问题是您想从第二个表达式(传递给 results.Where.Select() 的表达式)中引用一个表达式(过滤器),而 LINQ to SQL IQueryable 提供程序没有不知道如何获得它的价值。

您需要做的是从头开始编写 Select 表达式,以便内联作为您的动态过滤器的表达式。对于匿名类型,这可能会更加困难,我不确定。刚找到下面这篇文章,好像解释的很好:http://www.codeproject.com/KB/linq/rewrite_linq_expressions2.aspx

【讨论】:

【参考方案2】:

我从 MSDN 中得到的东西:这个想法是你只需将它指向一个现有的函数:

使用系统;

公共类 GenericFunc


   public static void Main()
   
      Func<string, string> convertMethod = UppercaseString;
   

   private static string UppercaseString(string inputString)
   
      return inputString.ToUpper();
   

我相信还有其他方法。我记得做过类似的事情

new Func<WorkItem, bool>((item => item.projectId == criteria.ProjectId))

但我不确定。再说了,我很确定你需要“新”,希望这会有所帮助:)

【讨论】:

以上是关于如何将 Predicate<T> 传递给 Linq to SQL 中的 Where() 方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何有条件地替换Collection中的值,例如replaceIf(Predicate<T>)?

为啥 Java 8 的 Predicate<T> 不扩展 Function<T, Boolean>

IEnumerable<T>.Contains with predicate

ActionAction<T>Func<T>Predicate<T>

使用函数式接口

如何将 Rc<RefCell<dyn T>> 传递给想要 &dyn T 的 fn?