我编写了一个 Linq 查询来对多个列进行外部联接。我的问题是我想或列。换句话说,我需要加入条件:
on Bar.Id equals Foo.BarId1 or Bar.Id equals Foo.BarId2
我在此站点上看到的一些示例使用匿名类型来创建 AND 条件,但我无法弄清楚如何使用匿名类型构造 OR,甚至是否可能。我找不到匹配的例子。
我的查询:
var data = (from f in Foos
join b in Bars on f.BarId1 equals b.Id into tb
from xb in tb.DefaultIfEmpty()
join b in Bars on f.BarId2 equals b.Id into tb2
from xb2 in tb2.DefaultIfEmpty()
select new { Foo = f, Bar1 = xb, Bar2 = xb2 });
这行得通,但我觉得这不是最好的解决方案
编辑
我说得太早了。它不起作用:当 Foo.BarId1 指向一个有效的 Bar,而 Foo.BarId2 没有,它实际上为 Bar1 和 Bar2 返回相同的 Bar。在这种情况下,我期望 Bar1 有效,而 Bar2 为空。
编辑
我越来越近了。这是我最新的查询:
var data = from f in Foos
from b in Bars.Where(x => x.Id == p.BarId1 || x.Id == p.BarId2).DefaultIfEmpty()
select new { Foo = p, Bars = b };
我期待它回来:
Foo Bar
f1 b1
b2
我得到的是:
Foo Bar
f1 b1
f1 b2
编辑
我终于找到了返回我想要的查询:
var data = from f in Foos
select new
{
Foo = f,
Bar1 = Bars.FirstOrDefault(x => x.Id == f.Bar1Id),
Bar2 = Bars.FirstOrDefault(x => x.Id == f.Bar2Id)
};
仍然想知道我可以对此做出的任何改进。
最终编辑
我回到了原来的查询:
var data = (from f in Foos
join b in Bars on f.BarId1 equals b.Id into tb
from xb in tb.DefaultIfEmpty()
join b in Bars on f.BarId2 equals b.Id into tb2
from xb2 in tb2.DefaultIfEmpty()
select new { Foo = f, Bar1 = xb, Bar2 = xb2 });
事实证明这实际上是有效的,但是我的 Linqpad 测试中的一个错误让我认为它不是。
它也比前一个更有效 - 在 SQL Profiler 中,我可以看到它生成 1 个 SQL 选择,而前一个生成 3*n 选择(每个 Foo 选择是否有 2 个 Bar 选择)