加入一对多关系的两个表,并从多面选择最新的

时间:2019-01-31 11:55:47

标签: c# linq entity-framework-core

我有两个表:Patient和PatientVisits。患者可以进行多次探访。 C#中有相应的Model类。

我如何编写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 :(得分:2)

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

答案 1 :(得分:1)

您可以这样写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,

};

答案 2 :(得分:0)

我的建议是:

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

    }
}

答案 3 :(得分:0)

如果您的类定义具有虚拟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(),
    });

如果您不能使用虚拟ICollection,则必须自己进行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(),
    });