【问题标题】:Join two tables with one to many relationship and pick latest from multiple side加入两个具有一对多关系的表并从多个方面选择最新的
【发布时间】:2019-01-31 11:55:46
【问题描述】:

我有两个表: PatientVisits 和 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"

【问题讨论】:

    标签: c# linq entity-framework-core


    【解决方案1】:
    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();
    

    【讨论】:

    • Slava:我收到一个错误:InvalidOperationException: No row is available
    • @PraveenRay,向我们展示您的上下文和上下文创建代码。
    • @PraveenRay,有没有内部异常?
    • Slava,它来自驱动程序:InvalidOperationException:没有行可用 NpgsqlDataReader.cs 中的 Npgsql.NpgsqlDataReader.CheckRow() NpgsqlDataReader.cs Npgsql.NpgsqlDefaultDataReader 中的 Npgsql.NpgsqlDataReader.CheckRowAndOrdinal(int ordinal)。 NpgsqlDefaultDataReader.cs 中的 GetFieldValue(int 列)
    【解决方案2】:

    你可以这样写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,
    
    };
    

    【讨论】:

      【解决方案3】:

      我的建议是:

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-24
          • 2013-01-11
          • 1970-01-01
          • 1970-01-01
          • 2020-11-08
          • 2016-11-10
          相关资源
          最近更新 更多