假设我有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表正在加入两个标题(不是问题)和detail1。如果detail1在detail2中没有日期记录,则detail2记录将不会出现在结果中。使用“select new {}等于new {}”不允许我在等于之前使用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...
}
答案 0 :(得分:2)
要实现具有任意条件的连接,您需要使用另一个from
子句和where
来处理您的情况。我不确定是否与Linq to SQL一起使用将生成哪种类型的SQL,使用我的FullOuterJoin / LeftOuterJoin IQueryable
扩展可能会更好。
var ans = from h in header
join d1 in detail1 on h.id equals d1.id into hd1j
from hd1 in hd1j.DefaultIfEmpty()
from d2 in detail2 where h.id == d2.id && (hd1?.date == null || hd1.date == d2?.date)
select new { h.id, h.label, date = hd1?.date ?? d2?.date, value1 = hd1?.value, value2 = d2?.value };
对于我的Enumerable
测试,我输入了条件运算符。如果针对IQueryable
进行测试(例如Linq to SQL),则应删除它们。