8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

实体框架中使用 OR 条件的动态查询

zest16 2月前

80 0

我正在创建一个搜索数据库的应用程序,并允许用户动态添加任何条件(大约 50 个可能),类似于以下 SO 问题:使用创建动态查询

我正在创建一个搜索数据库的应用程序,并允许用户动态添加任何条件(大约 50 个),就像以下 SO 问题一样: 使用实体框架创建动态查询 。我目前正在进行一个检查每个条件的搜索,如果它不为空,它会将其添加到查询中。

C#

var query = Db.Names.AsQueryable();
  if (!string.IsNullOrWhiteSpace(first))
      query = query.Where(q => q.first.Contains(first));
  if (!string.IsNullOrWhiteSpace(last))
      query = query.Where(q => q.last.Contains(last));
  //.. around 50 additional criteria
  return query.ToList();

此代码在 SQL Server 中产生类似于以下内容的内容(为了便于理解,我进行了简化)

SQL

SELECT
    [Id],
    [FirstName],
    [LastName],
    ...etc
FROM [dbo].[Names]
WHERE [FirstName] LIKE '%first%'
  AND [LastName] LIKE '%last%'

我现在正在尝试添加一种方法,通过实体框架用 C# 生成以下 SQL,但使用 OR 而不是 AND ,同时仍然保留动态添加条件的能力。

SQL

SELECT
    [Id],
    [FirstName],
    [LastName],
    ...etc
  FROM [dbo].[Names]
WHERE [FirstName] LIKE '%first%'
  OR [LastName] LIKE '%last%' <-- NOTICE THE "OR"

通常,查询的条件不会超过两三个项目,但将它们组合成一个巨大的查询不是一个选择。我尝试过 concat、union 和 intersect,它们都只是复制查询并使用 UNION 将它们连接起来。

是否有一种简单干净的方法可以使用实体框架向动态生成的查询添加“OR”条件?

使用我的解决方案进行编辑 - 2015 年 9 月 29 日

自从发布这篇文章以来,我注意到这个问题引起了一些关注,所以我决定发布我的解决方案

// Make sure to add required nuget
// PM> Install-Package LinqKit

var searchCriteria = new 
{
    FirstName = "sha",
    LastName = "hill",
    Address = string.Empty,
    Dob = (DateTime?)new DateTime(1970, 1, 1),
    MaritalStatus = "S",
    HireDate = (DateTime?)null,
    LoginId = string.Empty,
};

var predicate = PredicateBuilder.False<Person>();
if (!string.IsNullOrWhiteSpace(searchCriteria.FirstName))
{
    predicate = predicate.Or(p => p.FirstName.Contains(searchCriteria.FirstName));
}

if (!string.IsNullOrWhiteSpace(searchCriteria.LastName))
{
    predicate = predicate.Or(p => p.LastName.Contains(searchCriteria.LastName));
}

// Quite a few more conditions...

foreach(var person in this.Persons.Where(predicate.Compile()))
{
    Console.WriteLine("First: {0} Last: {1}", person.FirstName, person.LastName);
}
帖子版权声明 1、本帖标题:实体框架中使用 OR 条件的动态查询
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由zest16在本站《asp.net-mvc》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 是否有一种简单干净的方法可以使用实体框架向动态生成的查询添加“OR”条件?

    是的,您可以通过简单地依赖 where 包含单个布尔表达式的单个子句来实现这一点,该表达式的 OR 各个部分在运行时动态地被“禁用”或“启用”,从而避免必须安装 LINQKit 或编写自定义谓词构建器。

    参考你的例子:

    var isFirstValid = !string.IsNullOrWhiteSpace(first);
    var isLastValid = !string.IsNullOrWhiteSpace(last);
    
    var query = db.Names
      .AsQueryable()
      .Where(name =>
        (isFirstValid && name.first.Contains(first)) ||
        (isLastValid && name.last.Contains(last))
      )
      .ToList();
    

    根据先前评估的前提(例如 where 动态地打开或关闭过滤表达式的 OR 部分 isFirstValid

    例如,如果 短路FirstValid 不是 true ,则被 name.first.Contains(first) is既不会被执行,也不会影响结果集。此外,EF Core DefaultQuerySqlGenerator 在执行之前 进一步 优化和减少 where 其中的布尔表达式 false && x || true && y || false && z 可以 y 通过简单的静态分析将其简化为简单)。

    请注意:如果所有前提都不为 true ,则结果集将为空 — 我认为这是您的情况所需的行为。但是,如果您出于某种原因更喜欢从源中选择所有元素 IQueryable ,则可以将最终变量添加到表达式中以求值 true (例如, .Where( ... || shouldReturnAll) 使用 var shouldReturnAll = !(isFirstValid || isLastValid) 或类似的东西)。

    最后一点:这种技术的缺点是,它迫使您构建一个“集中式”布尔表达式,该表达式位于查询所在的同一方法主体中(更准确地说是 where 查询的一部分)。如果您出于某种原因想要分散谓词的构建过程并将它们作为参数注入或通过查询构建器链接它们,那么您最好坚持使用谓词构建器,如其他答案中所建议的那样。否则,请享受这种简单的技术 :)

返回
作者最近主题: