LINQ中的可扩展关系划分

本文关键字:关系 划分 可扩展 LINQ | 更新日期: 2023-09-27 17:50:16

在本例中,类IcdPatient表示Patient表(在本例中未显示)和查找表Icd之间的多对多关系。

public class IcdPatient
    {
        public int PatientId { get; set; }
        public int ConditionCode { get; set; }
        public static List<IcdPatient> GetIcdPatientList()
        {
            return new List<IcdPatient>()
            {
                new IcdPatient { PatientId = 100, ConditionCode = 111 },
                new IcdPatient { PatientId = 100, ConditionCode = 222 },
                new IcdPatient { PatientId = 200, ConditionCode = 111 },
                new IcdPatient { PatientId = 200, ConditionCode = 222 },
                new IcdPatient { PatientId = 3, ConditionCode = 222 },
            };
        }
    }
    public class Icd
    {
        public int ConditionCode { get; set; }
        public string ConditionName { get; set; }
        public static List<Icd> GetIcdList()
        {
            return new List<Icd>()
            {
                new Icd() { ConditionCode =111, ConditionName ="Condition 1"},
                new Icd() { ConditionCode =222, ConditionName ="Condition 2"},
            };
        }
    }

我希望用户能够输入尽可能多的条件,并获得一个LINQ对象返回,告诉他们有多少PatientId满足该查询。我想到了:

List<string> stringFilteredList = new List<string> { "Condition 1", "Condition 2" };
            List<int> filteringList = new List<int> { 111,222 };
            var manyToMany = IcdPatient.GetIcdPatientList();
            var icdList = Icd.GetIcdList();
            /*Working method without joining on the lookup table*/
            var grouped = from m in manyToMany
                          group m by m.PatientId into g
                          where g.Count() == filteringList.Distinct().Count()
                          select new
                          {
                              PatientId = g.Key,
                              Count = g.Count()
                          };
            /*End*/
            foreach (var item in grouped)
            {
                Console.WriteLine(item.PatientId);
            }

假设IcdPatient在两个字段上都有一个复合主键,因此我们知道每一行都是唯一的。如果我们在filteringList中找到不同数量的条目,并对PatientId出现的次数进行计数,这意味着我们找到了所有符合所有条件的人。因为代码可能很深奥,我想做一些像将ConditionName中的用户表设置为Icd类型,并执行相同的操作。我很少这样使用LINQ,我收集到:

 List<int> filteringList = new List<int> { 111,222 };
            List<string> stringFilteredList= new List<string>{"Condition 1","Condition 2" };
            filteringList.Distinct();
            var manyToMany = IcdPatient.GetIcdPatientList();
            var icdList = Icd.GetIcdList();
            /*Working method without joining on the lookup table*/
            var grouped = from m in manyToMany
                          join i in icdList on 
                          m.ConditionCode equals i.ConditionCode
                          //group m by m.PatientId into g
                          group new {m,i} by new { m.ConditionCode }into g
                          where g.Count() == filteringList.Distinct().Count()
                          select new
                          {
                              Condition = g.Key.ConditionCode
                          };
            /*End*/

却不能让任何东西工作。这实际上是在我的第一个查询之上的连接,但是我没有得到我需要分组的内容。

LINQ中的可扩展关系划分

在这种情况下,您不需要对任何内容进行分组,只需使用join和contains:

List<string> stringFilteredList= new List<string>{"Condition 1","Condition 2" };
var patients = 
    from icd in Icd.GetIcdList()
    join patient in IcdPatient.GetIcdPatientList() on icd.ConditionCode equals patient.ConditionCode
    where stringFilteredList.Contains(icd.ConditionName)
    select patient.PatientId;

假设IcdPatient在两个字段上都有一个复合主键,因此我们知道每一行都是唯一的。如果我们在filteringList中找到不同数量的条目,并对PatientId出现的次数进行计数,这意味着我们已经找到了具有所有条件的所有人。因为代码可能很深奥,所以我想做一些事情,比如让ConditionName中的用户表在类型Icd中,并执行相同的操作。

我相信你是在问:

给定一个ConditionCode s列表,返回一个PatientId s列表,其中每个患者具有列表中的所有病症。

在这种情况下,最简单的方法是按Id对IcdPatients表进行分组,这样我们就可以通过查看一次来了解患者的所有病情。然后我们检查我们正在寻找的每个ConditionCode都在组中。在代码中,它看起来像:

var result = IcdPatient.GetIcdPatientList()
                    // group up all the objects with the same PatientId
                    .GroupBy(patient => patient.PatientId)
                    // gather the information we care about into a single object of type {int, List<int>}
                    .Select(patients => new {Id = patients.Key,
                                            Conditions = patients.Select(p => p.ConditionCode)})
                    // get rid of the patients without every condition
                    .Where(conditionsByPatient =>
                            conditionsByPatient.Conditions.All(condition => filteringList.Contains(condition)))
                    .Select(conditionsByPatient => conditionsByPatient.Id);

查询格式如下:

var groupedInfo = from patient in IcdPatient.GetIcdPatientList()
                  group patient by patient.PatientId
                    into patients
                    select new { Id = patients.Key,
                                 Conditions = patients.Select(patient => patient.ConditionCode) };
var resultAlt = from g in groupedInfo
                where g.Conditions.All(condition => filteringList.Contains(condition))
                select g.Id;

编辑:如果你也想让你的用户指定ConditionName而不是ConditionId,那么只需从一个转换到另一个,将结果存储在filteringList中,像这样:

var conditionNames = // some list of names from the user
var filteringList = Icd.GetIcdList().Where(icd => conditionNames.Contains(icd.ConditionName))
                                    .Select(icd => icd.ConditionCode);