c# - 如何编写 SQL 交叉联接的 Linq 表达式?

标签 c# linq linq-to-entities entity-framework-5

我正在创建一个报告,根据用户定义的过滤条件列出数据库中的人员。例如,我可以按姓名、年龄等进行过滤。

var people = db.People.AsQueryable();
if (filterByName)
  people = people.Where(p => p.LastName.Contains(nameFilter));
if (filterByAge)
  people = people.Where(p => p.Age == age);

现在,过滤标准之一是显示尚未进行所需免疫接种的人员。我有 Immunization 的表格和PersonImmunization (在 PersonID, ImmunizationID 上具有唯一索引)。如果有人遗漏了任何PersonImmunization记录,或者接受的剂量数量符合要求的,应包括在内,否则不包括。

如果我编写 SQL 查询,它将是:

select p.*
from Person p
cross join Immunization i
left join PersonImmunization pi 
  on pi.PersonID = p.ID and pi.ImmunizationID = i.ID
where pi.ID is null or pi.Doses < i.RequiredDoses;

现在,为了使这部分成为我的 where 子句,我需要使用 Expression 来表达它谓词:

if (filterByImmunizations) {
  Expression<Func<Person, bool>> nonCompliantImmunization = 
    person => <now what?>;
  people = people.Where(nonCompliantImmunization);
}

我遇到的第一个问题是如何将免疫接种到表达中。然后,一旦我有了它,我怀疑找到不合规的人可能会更直接,但如果您可以将其包含在您的答案中,我将非常感激!

编辑:有人要求我解释为什么我如此坚定地使用Expression<Func<Person, bool>>来获得解决方案。 。原因是因为我已经构建了一个完整的通用框架,用于在几个不同的上下文中编写复杂的、用户定义的查询。为了让您了解引擎内部的内容,下面是我的基类内部的一个片段:

public abstract class QueryBuilder<T> where T : EntityObject {

  public static IQueryable<T> FilterQuery(IQueryable<T> query, IEnumerable<QueryConditionLite> filters, bool anyConditionSufficient) {
    ...
  }

  protected Expression<Func<TBase, bool>> GetPredicate(Expression<Func<TBase, double>> expression, IQueryCondition condition) { 
    ... 
  }
}

然后我有一个 PersonQueryBuilder : QueryBuilder<Person> ,并且在其中我想创建一个过滤器来显示不符合免疫要求的人。我想您会同意查询语法并不能解决问题。

最佳答案

我将其视为多部分连接:

var nonCompiantImmunization =
  from p in Persons
  from i in Immunizations
  let pi = PersonImmunizations.Where(x =>
    x.ImmunizationID == i.ID && x.PersonID == p.ID)
  where !pi.Any() || pi.Sum(x => x.Doses) < i.RequiredDoses
  select new { p, i };

编辑:使其适合 Expression<Func<Person, bool>>约束,我想你可以将其改写为:

Expression<Func<Person, bool>> nonCompliantImmunization = 
  person => (
      from i in Immunizations
      let pi = PersonImmunizations.Where(x =>
        x.ImmunizationID == i.ID && x.PersonID == person.ID)
      where !pi.Any() || pi.Sum(x => x.Doses) < i.RequiredDoses
      select true
    ).Any();

关于c# - 如何编写 SQL 交叉联接的 Linq 表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18062110/

相关文章:

c# - 如何从 List<String[]> 创建一个 csv 文件

c# - 如何在 AOT 平台上在运行时生成任何泛型类型?

c# - Linq to Sql : how to get data - one to many

c# - 使用 LINQ to SQL 查询中的数据填充 Excel

entity-framework - DbContext 释放后枚举成功

c# - 从 asp.net mvc 5 中的字符串转换日期时间时转换失败

c# - 在 TextBlock 中环绕文本

c# - 从列表中获取不同的项目

linq - 在 linq 查询中使用字典

c# - 格式化 List<T> 以连接字段