如何使用Linq在包含DBNull值的多个列上连接多个DataTable

时间:2017-04-20 17:09:03

标签: c# linq datatable

我有3个DataTable对象,其中包含我想要加入的关系数据。 第一个模式看起来像

DataTable parent = new DataTable();
parent.Columns.Add("Id1", typeof(string));
parent.Columns.Add("Id2", typeof(string));
// more metadata

其中任何一个ID可能是DBNull,但不是两者。

两个chlid表具有相同的架构。

DataTable child = new DataTable();
child.Columns.Add("Id1", typeof(string));
child.Columns.Add("Id2", typeof(string));
child.Columns.Add("BeginDate", typeof(DateTime));
child.Columns.Add("SomeData", typeof(float));
// more data

我有一个函数,它将所有三个DataTables作为输入,并且应该返回连接表。

var dataToReturn =  // will be converted to a DataTable later.
    from
        p in parent.AsEnumerable()
    join c1 in child1.AsEnumerable()
        on new {
            Id1 = p["Id1"],
            Id2 = p["Id2"],
        }
        equals new {
            Id1 = c1["Id1"],
            Id2 = c1["Id2"],
        }
    join c2 in child2.AsEnumerable()
        on new {
            Id1 = p["Id1"],
            Id2 = p["Id2"],
            BeginDate = c1["BeginDate"],
        }
        equals new {
            Id1 = p["Id1"],
            Id2 = p["Id2"],
            BeginDate = c1["BeginDate"],
        }
    select new {
        Id1 = p["Id1"],
        Id2 = p["Id2"],
        BeginDate = c1["BeginDate"],
        Child1Data = c1["SomeData"],
        Child2Data = c2["SomeData"],
    }

但是,即使在这些条件上有许多非空值匹配,也不会返回任何结果。

如果我正在编写SQL(使用"与#34;不同,来自Postgres以使null = null为了简洁而返回true),我会写

select
    p.Id1,
    p.Id2,
    c1.BeginDate,
    c1.SomeData as Child1Data,
    c2.SomeData as Child2Data
from
    Parent p
    join Child1 c1
        on c1.Id1 is not distinct from p.Id1
        and c1.Id2 is not distinct from p.Id2
    join Child2 c2
        on c2.Id1 is not distinct from p.Id1
        and c2.Id2 is not distinct from p.Id2
        and c2.BeginDate = c1.BeginDate

请注意"的使用与"不同。 over" ="对于Id字段,因为我想要" DBNull.Value == DBNull.Value"返回真实。

我的问题:

这可能与Linq的内存DataTables有关吗? Linq如何在这些查询中处理DBNull.Value比较?

1 个答案:

答案 0 :(得分:0)

Linq会正确地将DBNull.Value与另一个DBNull.Value匹配。我相信那是你的问题而不是加入第二张儿童表,因为这是微不足道的

DataTable parent = new DataTable();
parent.Columns.Add("Id1", typeof(string));
parent.Columns.Add("Id2", typeof(string));
DataRow r1 = parent.NewRow();
r1["Id1"] = "1";
r1["Id2"] = DBNull.Value;
parent.Rows.Add(r1);
DataRow r3 = parent.NewRow();
r3["Id1"] = "1";
r3["Id2"] = "2";
parent.Rows.Add(r3);

DataTable child1 = new DataTable();
child1.Columns.Add("Id1", typeof(string));
child1.Columns.Add("Id2", typeof(string));
child1.Columns.Add("BeginDate", typeof(DateTime));
child1.Columns.Add("SomeData", typeof(float));
DataRow r2 = child1.NewRow();
r2["Id1"] = "1";
r2["Id2"] = DBNull.Value;
child1.Rows.Add(r2);
DataRow r4 = child1.NewRow();
r4["Id1"] = "1";
r4["Id2"] = "2";
child1.Rows.Add(r4);

var dataToReturn =
    from
    p in parent.AsEnumerable()
    join c1 in child1.AsEnumerable()
    on new { Id1 = p["Id1"], Id2 = p["Id2"] }
    equals new { Id1 = c1["Id1"], Id2 = c1["Id2"] }
    select new
    {
        Id1 = p["Id1"],
        Id2 = p["Id2"]
    };

foreach(var l in dataToReturn)
{
    Console.WriteLine(l.Id1 + "|" + l.Id2);
}

Console.ReadKey();

输出:

1|
1|2