创建一个公共谓词函数

首先,我不确定用什么术语来提出这个问题,这可能就是为什么我没有找到自己搜索的答案。

所以我正在使用Linq to SQL(C#,。Net 4),我希望得到一个符合条件的所有用户的列表,其基本内容我会做这样的事情:

var users = DataContext.Users.Where(x => x.Criteria1 == "something"); 

但是在这种情况下我想要匹配一些字段,事情是这些特殊字段是一个常见的检查,我希望能够创建一个专用函数,我可以在任何用户查询中使用它来检查这个比赛。

试着解释一下,让我们举一个例子:假设用户有5个标志,我想要一个常见的检查,看看是否设置了这些标志。 所以我可以这样写我的查询:

 var users = DataContext.Users.Where(x => x.Flag1 || x.Flag2 || x.Flag3 || x.Flag4 || x.Flag5); 

但我想做的是分开“5旗检查”,这样我也可以在其他查​​询中使用它,最终我想使用类似的东西:

 var users = DataContext.Users.Where(x => x.Criteria1 == "something" && CheckForFlags(x)); 

我通过这样的函数尝试了这个:

 static bool CheckForFlags(User user) { return user.Flag1 || user.Flag2 || user.Flag3 || user.Flag4 || user.Flag5; } 

但是我收到一个错误:

“方法’布尔CheckForFlags(用户)’没有支持的SQL转换。”

……这是有道理的,但是我能做些什么才能让这项工作按我想要的方式进行? 或者这是一个限制,因为我使用Linq to SQL,实际上是可以使用Linq到Objects的东西?

关于LINQ to SQL如何处理表达式的巧妙之处在于,您实际上可以在代码中的其他位置构建表达式并在查询中引用它们。 你为什么不尝试这样的事情:

 public static class Predicates { public static Expression> CheckForFlags() { return (user => user.Flag1 || user.Flag2 || user.Flag3 || user.Flag4 || user.Flag5); } public static Expression> CheckForCriteria(string value) { return (user => user.Criteria1 == value); } } 

定义谓词后,在查询中使用它们非常容易。

 var users = DataContext.Users .Where(Predicates.CheckForFlags()) .Where(Predicates.CheckForCriteria("something")); 

你试过PredicateBuilder吗? 我在一年多的时间里没有使用它,但我发现它在编写“或在哪里”查询时有效。

http://www.albahari.com/nutshell/predicatebuilder.aspx

他们页面的一个例子:

 IQueryable SearchProducts (params string[] keywords) { var predicate = PredicateBuilder.False(); foreach (string keyword in keywords) { string temp = keyword; predicate = predicate.Or (p => p.Description.Contains (temp)); } return dataContext.Products.Where (predicate); } 

据我所知,有两种可能的方法可以做到这一点。

快速简单的方法是在SQL执行后过滤结果,如下所示:

 var users = DataContext.Users.Where(x => x.Criteria1 == "something"); .ToEnumerable() .Where(x => CheckForFlags(x)); 

然而,这在性能方面非常差。 它将返回仅与第一个条件匹配的数据库中的所有行,然后在客户端的内存中过滤结果。 function性,但远非最佳。

第二个更高性能的选项是在数据库本身上创建一个UDF并从LINQ调用它。 例如,请参阅此问题 。 明显的缺点是它将代码移动到数据库中,没有人喜欢这样做(出于许多正当理由)。

可能还有其他可行的解决方案,但这些是我所知道的唯一两种解决方案。

认为这会有效,我我已经在我的Linq-to-SQL项目中使用过了,但是我无法找到一个例子。 如果没有,请告诉我。


而不是创建一个函数,在Users对象上创建一个新属性:

 partial class Users { bool CheckForFlags { get { return Flag1 || Flag2 || Flag3 || Flag4 || Flag5; } } } 

那你应该可以做到

 var users = DataContext.Users.Where(x => x.CheckForFlags); 

就像你说的,这是一个限制,因为你使用Linq to SQL。

这样的东西应该工作:

 var users = DataContext.Users.Where(x => x.Criteria1 == "something") .ToArray() .Where(x => CheckForFlags(x));