LINQ中的可扩展关系划分

时间:2014-03-14 20:21:20

标签: c# linq relational-division

在此示例中,类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 s满足该查询。我想出了:

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出现的次数,则表示我们找到了所有具有所有条件的人。因为代码可能是深奥的,我想做类似的事情 让用户表在Icd类型的ConditionName中执行相同的操作。我没有这么多地使用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*/

但无法正常工作。这基本上是我第一次查询时的联接,但我没有得到我需要分组的内容。

2 个答案:

答案 0 :(得分:0)

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

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;

答案 1 :(得分:0)

  

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

我相信你在问:

  

给定一个ConditionCode列表,返回PatientId个列表,其中每个病人都有列表中的所有条件。

在这种情况下,最简单的方法是按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);