简体   繁体   中英

C# Entity Framework OrderBy Children's Children's with a where clause

I have a pretty complicated linq statement that gets a list of people (using Entity Framework) and I want to add an OrderBy clause to the end, depending on which column the user has clicked on for sorting. I DON'T want to get all the people and then sort as there are potentially alot of people and we also do paging, so getting the data and then sorting/paging is not an option. It must therefore be done using LINQ to EF.

I have managed to get the search criteria that filters based on the status of the user's current vaccination status, but I am unable to "convert" that to an OrderBy statement

The data I am getting relates to COVID vaccinations and whether the person's vaccination status is Full, Partial, Not Disclosed or None.

The Entity Framework LINQ statement with the Where clause looks like this and It is an IQueryable<Person> , not a 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)

From the above it will filter the people where their vaccination status is "Overdue". ie they have done either Partial or Full Vaccination but the cycle for this vaccination has been exceeded. There are 2 questions with questioncode's "qIDateP" (partial) and "qIDateF" (full).

I know the below OrderBy is completly wrong, but I want to do something like this so that all the people with overdue vaccination status's are at the top. I will then add several other OrderBy clauses such as "Current" using the same clause, just chainging the date expression eg DbFunctions.AddMonths(a.adate, procedureCycleDays) >= 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)

The Relationships for the EF Models is as follows:

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

A person can answer multiple Assessments over their life and can change their mind as to whether they want to disclose their vaccination status or not.

NOTE: We are using the latest Entity Framework 6.4.4

I hope someone can help me with the OrderBy clause as Im at a complete loss as to how to achieve this.

Well as far as I can tell you want to use orderBy and then simply fetch the first element, while you could simply fetch the first element with the same predicate dropping O(nlogn) complexity

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM