创建一个公共谓词函数
首先,我不确定用什么术语来提出这个问题,这可能就是为什么我没有找到自己搜索的答案。
所以我正在使用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));