30

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

所以我正在使用 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;
}

但我收到一个错误:

“方法 'Boolean CheckForFlags(User)' 不支持对 SQL 的转换。”

...这是有道理的,但是我可以做些什么来使这项工作按我想要的方式工作吗?或者这是一个限制,因为我使用的是 Linq to SQL,实际上它可以与 Linq to Objects 一起使用?

4

4 回答 4

53

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

public static class Predicates
{
    public static Expression<Func<User, bool>> CheckForFlags()
    {
        return (user => user.Flag1 || user.Flag2 || user.Flag3 ||
                        user.Flag4 || user.Flag5);
    }

    public static Expression<Func<User, bool>> CheckForCriteria(string value)
    {
        return (user => user.Criteria1 == value);
    }
}

一旦定义了谓词,就很容易在查询中使用它们。

var users = DataContext.Users
    .Where(Predicates.CheckForFlags())
    .Where(Predicates.CheckForCriteria("something"));
于 2012-11-01T16:18:05.823 回答
4

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

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

他们页面上的一个例子:

IQueryable<Product> SearchProducts (params string[] keywords)
{
  var predicate = PredicateBuilder.False<Product>();

  foreach (string keyword in keywords)
  {
    string temp = keyword;
    predicate = predicate.Or (p => p.Description.Contains (temp));
  }
  return dataContext.Products.Where (predicate);
}
于 2012-11-01T16:10:49.337 回答
0

认为这会起作用,并且我认为我已经在我的 Linq-to-SQL 项目中使用了它,但是我找不到一个示例。如果没有,请告诉我。


与其创建函数,不如在Users对象上创建一个新属性:

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

那么你应该能够做到

var users = DataContext.Users.Where(x => x.CheckForFlags);
于 2012-11-01T16:08:23.633 回答
0

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

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

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

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

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

很可能还有其他可行的解决方案,但这是我所知道的仅有的两个。

于 2012-11-01T16:08:56.850 回答