Соедините две таблицы с отношениями один-ко-многим и выберите последние с разных сторон - PullRequest
0 голосов
/ 31 января 2019

У меня есть две таблицы: Patients и PatientVisits.Пациент может иметь много посещений.Существуют соответствующие классы моделей в C #.

Как мне написать запрос Linq, чтобы получить каждого пациента и дату его последнего посещения?

Необработанный SQL, который делает это:

select max(p."FirstName"), max(p."LastName"), max(pv."VisitDate")
from "Patients" p 
left outer join "PatientVisits" pv ON pv."PatientID" = p."ID" 
group by p."ID"

Ответы [ 4 ]

0 голосов
/ 31 января 2019

Если в ваших определениях классов есть виртуальная коллекция ICollection, вы можете использовать их:

public class Patient
{
    public int Id { get; set; }
    ...

    // every Patient has zero or more Visits (one-to-many)
    public virtual ICollection<Visit> Visits {get; set;}
}

public class Visit
{
    public int Id {get; set;}
    public DateTime VisitDate { get; set; }
    ...

    // Every Visit is done by exactly one Patient, using foreign key
    public int PatiendId {get; set;}
    public virtual Patient Patient { get; set; }
}

Требование: укажите для каждого пациента время его последнего посещения

var result = dbContext.Patients
    .Where(patient => ...)           // only if you don't want all Patients
    .Select(patient => new
    {
        // Select from every Patient only the properties you plan to use
        Id = patient.Id,
        Name = patient.Name,
        ...
        LastVisitTime = patient.Visits
            .OrderByDescenting(visit => visit.VisitDate)
            .FirstOrDefault(),
    });

Если вы не можете использовать виртуальные ICollections, вам придется выполнить GroupJoin самостоятельно:

var result = dbContext.Patients.GroupJoing(dbContext.Visits,
    patient => patient.Id,             // from every Patient take the Id
    visit => visit.PatientId,          // from every Visit take the PatientId,

    (patient, visits) => new           // use every patient with all his matching Visits
    {                                  // to make a new object
         Id = patiend.Id,
         Name = patient.Name,
         ...

         LastVisit = visits.OrderByDescending(visit => visit.VisitDate)
                     .FirstOrDefault(),
    });
0 голосов
/ 31 января 2019
var answer = (from p in context.Patients
              join v in context.PatientVisits on p.ID equals v.PatientID into subs
              from sub in subs.DefaultIfEmpty()
              group sub by new { p.ID, p.FirstName, p.LastName } into gr
              select new 
              {
                  gr.Key.FirstName,
                  gr.Key.LastName,
                  VisitDate = gr.Max(x => x == null ? null : (DateTime?)x.VisitDate)
              }).ToList();
0 голосов
/ 31 января 2019

Мое предложение будет:

public class Patient
{
    public int PatientId { get; set; }
    public string Name { get; set; }
}

public class PatientVisit
{
    public Patient Patient { get; set; }
    public DateTime VisitDate { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Patient p1 = new Patient();
        p1.PatientId = 1;
        p1.Name = "Harry";

        Patient p2 = new Patient();
        p2.PatientId = 2;
        p2.Name = "John";

        List<PatientVisit> visits = new List<PatientVisit>();
        visits.Add(new PatientVisit
        {
            Patient = p1,
            VisitDate = DateTime.Now.AddDays(-5)
        });

        visits.Add(new PatientVisit
        {
            Patient = p1,
            VisitDate = DateTime.Now
        });

        visits.Add(new PatientVisit
        {
            Patient = p2,
            VisitDate = DateTime.Now.AddDays(-1)
        });


        var q = (from t in visits
                 select new
                 {
                     t.Patient.Name,
                     t.Patient.PatientId,
                     t.VisitDate
                 }).OrderByDescending(t=>t.VisitDate).GroupBy(x => new { x.PatientId });

        foreach (var item in q)
        {
            Console.WriteLine(item.FirstOrDefault().Name + ", " + item.FirstOrDefault().VisitDate);
        }

    }
}
0 голосов
/ 31 января 2019

Вы можете написать Linq как этот

from p in Patients
join pv in PatientVisits on p.PatientID equals pv.id into jointable
from z in jointable.DefaultIfEmpty()
select new
{
  p.FirstName, 
  p.LastName,
  pv.VisitDate,

};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...