简体   繁体   English

Linq中的多个左联接和组合等于和不等于

[英]Multiple left joins and combining equals and not equals in Linq

I'm trying to join two DataTables so that the first table is LEFT-joined to the second table twice on the CustID column. 我试图联接两个DataTable,以使第一个表在CustID列上两次左联接到第二个表。 The first plant table must match the PlantID from the animal table and the second plant table in the join must NOT match the PlantID from the animal table. 第一个植物表必须与动物表中的PlantID匹配,并且联接中的第二个植物表必须与动物表中的PlantID不匹配。 However when I try this in Linq, it seems to ignore the where clause altogether. 但是,当我在Linq中尝试此操作时,它似乎完全忽略了where子句。

Animals: 动物:

ID | CustID | PlantID
=====================
1  |   1    | <null>
2  |   2    |    1
3  |   2    | <null>

Plants: 植物:

ID | CustID | Name
==================
 1 |    2   |  b1
 2 |    2   |  b2

In SQL the query I want would be: 在SQL中,我想要的查询将是:

SELECT    a.id, a.custid, p1.id AS PlantID1, p2.id AS PlantID2
FROM      animals a
LEFT JOIN plants p1 on a.custid = p1.custid AND a.plantid = p1.id
LEFT JOIN plants p2 on a.custid = p2.custid AND a.plantid != p2.id

Here is my code when trying it with linq to dataset: 这是我使用linq尝试到数据集时的代码:

        DataTable animals = new DataTable();
        animals.Columns.Add("id", typeof(int));
        animals.Columns.Add("custid", typeof(int));
        animals.Columns.Add("plantid", typeof(int));
        animals.Rows.Add(1, 1, DBNull.Value);
        animals.Rows.Add(2, 2, 1);
        animals.Rows.Add(3, 2, DBNull.Value);

        DataTable plants = new DataTable();
        plants.Columns.Add("id", typeof(int));
        plants.Columns.Add("custid", typeof(int));
        plants.Columns.Add("name", typeof(string));
        plants.Rows.Add(1, 2, "b1");
        plants.Rows.Add(2, 2, "b2");

        var test = from al in animals.AsEnumerable()
                   join bl in plants.AsEnumerable()
                   on new { x = al["custid"], y = al["plantid"] } equals new { x = bl["custid"], y = bl["id"] } into gj
                   join bl2 in plants.AsEnumerable()
                   on al["custid"] equals bl2["custid"] into gj2
                   from subbl in gj.DefaultIfEmpty()
                   from subbl2 in gj2.DefaultIfEmpty()
                   select new
                   {
                       aid = al["id"],
                       custid = al["custid"],
                       plantid1 = subbl == null ? DBNull.Value : subbl["id"],
                       plantName = subbl == null ? DBNull.Value : subbl["name"],
                       plantid2 = subbl2 == null ? DBNull.Value : subbl2["id"],
                       plantName2 = subbl2 == null ? DBNull.Value : subbl2["name"]
                   };
        var result = test.Where(st => st.plantid1 != st.plantid2).Cast<object>().ToList();

The result I get includes the following row, which I thought would be excluded by the Where clause: 我得到的结果包括以下行,我认为该行将被Where子句排除:

aid | custid | plantid1 | plantid2
==================================
 1  |   1    |
 2  |   2    |    1     |   1
 2  |   2    |    1     |   2
 2  |   2    |          |   1
 2  |   2    |          |   2

When I try it with linq to objects, the second row isn't present, which I expect. 当我对对象使用linq进行尝试时,第二行不存在,这是我期望的。 Here is my code using objects: 这是我使用对象的代码:

    class animal
    {
        public int id, custid;
        public int? plantid;
    }
    class plant
    {
        public int id;
        public int custid;
        public string name;
    }
    List<object> testStructs()
    {
        List<animal> animals = new List<animal>()
        {
            new animal() { id = 1, custid = 1, plantid = 0 }, 
            new animal() { id = 2, custid = 2, plantid = 1 }, 
            new animal() { id = 3, custid = 2 } 
        };
        List<plant> plants = new List<plant>() 
        { 
            new plant() { id = 1, custid = 2, name = "col1" }, 
            new plant() { id = 2, custid = 2, name = "col2" } 
        };
        var test = from al in animals.AsEnumerable()
                   join bl in plants.AsEnumerable()
                   on new { x = al.custid, y = al.plantid } equals new { x = bl.custid, y = (int?)bl.id } into gj
                   join bl2 in plants.AsEnumerable()
                   on al.custid equals bl2.custid into gj2
                   from subbl in gj.DefaultIfEmpty()
                   from subbl2 in gj2.DefaultIfEmpty()
                   select new
                   {
                       aid = al.id,
                       custid = al.custid,
                       plantid1 = subbl == null ? null : (int?)subbl.id,
                       plantName = subbl == null ? string.Empty : subbl.name,
                       plantid2 = subbl2 == null ? null : (int?)subbl2.id,
                       plantName2 = subbl2 == null ? string.Empty : subbl2.name
                   };

        return test.Where(st => st.plantid1 != st.plantid2 || st.plantid1 == null || st.plantid2 == null).Cast<object>().ToList();
    }

I worked out what I was doing wrong. 我弄清楚我做错了什么。 My where clause is comparing fields of an anonymous type, which are compared by reference. 我的where子句正在比较匿名类型的字段,这些字段通过引用进行比较。 The where clause should be where子句应该是

Where(st => !st.plantid1.Equals(st.plantid2))

to compare the values of those fields. 比较这些字段的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM