【发布时间】:2017-05-09 21:22:30
【问题描述】:
假设我有 3 个表格 - 1 个标题和 2 个详细信息:
标题表
id | label
1 | foo
2 | bar
详细信息 1 表
id | date | value
1 | 2015-01-01 | 5
详情2表
id | date | value
1 | 2015-01-01 | 7
2 | 2016-02-02 | 10
我想做一个连接所有三个的 linq 查询,但由于一个明细表没有另一张的记录,因此不会消除数据。结果应如下所示:
结果表
id | label | date | value1 | value2
1 | foo | 2015-01-01 | 5 | 7
2 | bar | 2016-02-02 | <null> | 10
因此,value1 为 null,而不是删除整行。
如果我在写 SQL,我可以写
select
h.id,
h.label,
coalesce(d1.date, d2.date) as date,
d1.value as value1,
d2.value as value2
from
header h
left join detail1 d1
on d1.id = h.id
left join detail2 d2
on d2.id = h.id
and (
d2.date = d1.date
or d1.date is null
)
是否可以使用 Linq 编写此代码?我正在使用“on new equals new”语法,当没有匹配的 detail1 记录时,我无法弄清楚如何保留 detail2 记录。
编辑:我觉得链接的答案只回答了我问题的左连接部分。我知道我可以在 linq 中加入,但是 detail2 表同时加入了 header(不是问题)和 detail1。如果 detail1 在 detail2 中没有日期的记录,则 detail2 记录将不会出现在结果中。使用“select new{} equals new{}”不允许我在equals之前使用detail2对象,所以我不能写
from
h in header.AsEnumerable()
join d1.AsEnumerable().DefaultIfEmpty()
on p.Id equals d1.Id
join d2.AsEnumerable().DefaultIfEmpty()
on new {
Id = h["Id"],
Date = d1["Date"] ?? d2["Date"], // Doesn't work, can't use d2 here.
} // d1 may not have a record, so there may not be a match
equals new {
Id = d2["Id"],
Date = d2["Date"],
}
select new {
// etc...
}
【问题讨论】:
-
LINQ 支持左连接。请参阅 lambda 语法中使用的 .GroupJoin(inner, key, key, result) 扩展方法,或经典 linq 中使用的 .DefaultIfEmpty()。您可以在this answer in question "LEFT OUTER JOIN in LINQ" 中看到后者——它是
from p in ps.DefaultIfEmpty(),ps连接将被转换为 LEFT JOIN。 -
这不是一个简单的左外连接,因为 LINQ 中的连接是等值连接,这在第二个
LEFT JOIN上有一个额外的条件。