C# 实体框架 OrderBy Children's Children's with a where 子句

Posted

技术标签:

【中文标题】C# 实体框架 OrderBy Children\'s Children\'s with a where 子句【英文标题】:C# Entity Framework OrderBy Children's Children's with a where clauseC# 实体框架 OrderBy Children's Children's with a where 子句 【发布时间】:2022-01-16 02:30:02 【问题描述】:

我有一个非常复杂的 linq 语句,它获取人员列表(使用实体框架),我想在末尾添加一个 OrderBy 子句,具体取决于用户单击哪个列进行排序。我不想让所有人都进行排序,因为可能有很多人,而且我们也进行分页,所以获取数据然后排序/分页不是一种选择。因此必须使用 LINQ to EF 来完成。

我已设法获得根据用户当前疫苗接种状态进行过滤的搜索条件,但我无法将其“转换”为 OrderBy 声明

我获得的数据与 COVID 疫苗接种有关,以及此人的疫苗接种状态是完全、部分、未披露还是无。

带有Where 子句的实体框架LINQ 语句如下所示,它是IQueryable<Person>,而不是List<Person>

people.Where(p => p.Encounters.Where(e =>
          e.EncounterItems.Any(ei => ei.PersonAssessments.Any(pa =>
          pa.Assessment.Questions.Any(q => q.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase) || q.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)))))
          .OrderByDescending(e => e.servicedt ?? e.planneddt).FirstOrDefault()
          .EncounterItems.Where(ei =>
          ei.PersonAssessments.Any(pa => pa.Answers.Any(a => a.adate.HasValue && DbFunctions.AddMonths(a.adate, procedureCycleDays) < DateTime.Today &&
          (a.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase) || (a.Question.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)
          && (!pa.Answers.Any(aa => aa.adate.HasValue && aa.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)))
          ))))).FirstOrDefault()
          != null)

它会从上面筛选出疫苗接种状态为“过期”的人。即他们已经进行了部分或全部疫苗接种,但已超过该疫苗接种的周期。问题代码的“qIDateP”(部分)和“qIDateF”(完整)有 2 个问题。

我知道下面的OrderBy 是完全错误的,但我想做这样的事情,以便所有疫苗接种状态过期的人都在顶部。然后,我将使用相同的子句添加其他几个OrderBy 子句,例如“Current”,只是链接日期表达式,例如DbFunctions.AddMonths(a.adate, procedureCycleDays) &gt;= DateTime.Today

people.OrderBy(p => p.Encounters.Where(e =>
       e.EncounterItems.Any(ei => ei.PersonAssessments.Any(pa =>
       pa.Assessment.Questions.Any(q => q.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase) || q.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)))))
       .OrderByDescending(e => e.servicedt ?? e.planneddt).FirstOrDefault()
       .EncounterItems.Where(ei =>
       ei.PersonAssessments.Any(pa => pa.Answers.Any(a => a.adate.HasValue && DbFunctions.AddMonths(a.adate, procedureCycleDays) < DateTime.Today &&
       (a.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase) || (a.Question.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)
       && (!pa.Answers.Any(aa => aa.adate.HasValue && aa.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)))
       ))))).FirstOrDefault()
       != null)

EF 模型的关系如下:

Person => Encounter => EncounterItem => PersonAssessment => Answer

一个人可以在一生中回答多项评估,并且可以改变他们是否要披露其疫苗接种状态的想法。

注意:我们使用的是最新的 Entity Framework 6.4.4

我希望有人可以帮助我处理 OrderBy 子句,因为我完全不知道如何实现这一点。

-----更新 1-------

到目前为止,我一直在使用它。

people.OrderBy(p => p.Encounters.Where(
              e => e.EncounterItems.Any(
                ei => ei.PersonAssessments.Any(
                  pa => pa.Assessment.Questions.Any(
                    q => q.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
                      || q.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase))))).OrderByDescending(e => e.servicedt ?? e.planneddt).FirstOrDefault() // you have 1 Encounters item
                .EncounterItems.DefaultIfEmpty().FirstOrDefault(
                  ei => ei.PersonAssessments.Any(
                    pa => pa.Answers.Any(
                      a => a.adate.HasValue
                      && DbFunctions.AddMonths(a.adate, procedureCycleDays) < DateTime.Today
                      && (a.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
                        || (a.Question.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)
                          && (!pa.Answers.Any(aa => aa.adate.HasValue && aa.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)))))))).Encounter.planneddt)

问题是所有“过期”记录都在底部,而不是顶部。如果我使用OrderByDescending,它似乎是正确的。我现在如何使用OrderBy 而不是OrderByDescending 将所有这些记录放在顶部。

------ UPDATE 2 最终解决方案 ------

根据下面的Margus 答案进行了几次更改后,我得到了最终更新的OrderBy。出于某种原因,我不得不OrderBydescending 才能获得我想要的记录。

people.OrderByDescending(p => p.Encounters.Where(
    e => e.EncounterItems.Any(
    ei => ei.PersonAssessments.Any(
    pa => pa.Assessment.Questions.Any(
    q => q.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
    || q.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase))))).OrderByDescending(e => e.servicedt ?? e.planneddt).FirstOrDefault() // you have 1 Encounters item.EncounterItems.DefaultIfEmpty().FirstOrDefault(
    ei => ei.PersonAssessments.Any(
    pa => pa.Answers.Any(
    a => a.adate.HasValue
    && DbFunctions.AddMonths(a.adate, procedureCycleDays) < DateTime.Today
    && (a.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
    || (a.Question.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)
    && (!pa.Answers.Any(aa => aa.adate.HasValue && aa.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)))))))).Encounter.planneddt)

现在我担心性能,哈哈……但这将是另一个 *** 搜索 :)

【问题讨论】:

【参考方案1】:

据我所知,你想使用 orderBy 然后简单地获取第一个元素,而你可以简单地获取具有相同谓词的第一个元素,降低 O(nlogn) 复杂度

var result = people.Where(
    p => p.Encounters.Where(
        e => e.EncounterItems.Any(
            ei => ei.PersonAssessments.Any(
                pa => pa.Assessment.Questions.Any(
                    q => q.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase) 
                      || q.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)))))
      .FirstOrDefault(e => e.servicedt ?? e.planneddt) // you have 1 Encounters item
      .EncounterItems.FirstOrDefault(
        ei => ei.PersonAssessments.Any(
            pa => pa.Answers.Any(
                a => a.adate.HasValue 
                    && DbFunctions.AddMonths(a.adate, procedureCycleDays) < DateTime.Today 
                      && (a.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase) 
                        || (a.Question.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)
                          && (!pa.Answers.Any(aa => aa.adate.HasValue && aa.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)))))))));

【讨论】:

太棒了!看到))))))))); 关巢会吓到我? 你肯定不会是认真的...就这么简单吗??我明天在工作中试试,让你知道它是怎么回事。感谢您的快速回复。 HHmmm... 我收到此错误: System.ArgumentException: 'DbSortClause 表达式必须具有可与顺序比较的类型。参数名称:key'有什么想法吗? 感谢 Margus 的帮助...我已使用最终更新的 OrderBy 编辑了我的问题

以上是关于C# 实体框架 OrderBy Children's Children's with a where 子句的主要内容,如果未能解决你的问题,请参考以下文章

具有实体框架并使用 orderby 和 skip/take 的规范模式

实体框架:查询子实体 [重复]

插入束数据 - 实体框架 C#

C#:更改实体框架的检索数据类型

C# 实体框架每个 HttpContext 仅使用一个 ObjectContext

C# 实体框架 - 优化/最佳实践