创建一个公共谓词函数

时间:2012-11-01 15:55:29

标签: c# linq-to-sql

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

所以我正在使用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 to Objects可以使用的东西吗?

5 个答案:

答案 0 :(得分:44)

关于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"));

答案 1 :(得分:4)

您是否尝试过PredicateBuilder?我在一年多的时间里没有使用过它,但我发现它在编写&#34;或者哪里&#34;查询。

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);
}

答案 2 :(得分: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);

答案 3 :(得分:0)

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

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

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

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

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

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

答案 4 :(得分:-1)

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

这样的事情应该可行:

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