我编写了一个Linq查询来对多个列进行外连接。我的问题是我想要OR列。换句话说,我需要连接条件:
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事件探查器中我可以看到它生成了1个SQL选择,与之前相比,它产生3 * n个选择(每个Foo选择都有2个Bar选择)
答案 0 :(得分:0)
如以下链接所示, LINQ 仅支持支持equal
。如果您需要任何其他类型的联接,请使用交叉联接,其中:
答案 1 :(得分:0)
LINQ还通过将连接放在Where子句中来支持ANSI-82语法。看看以下内容是否适合您:
var data = from f in Foos
from b in Bars
where f.Id == b.BarId1 || f.Id == b.BarId2
select new { Foo = p, Bars = bx };
我怀疑这只会给你一个内连接而不是外连接。你可能需要添加另一个where子句!包含根据你的要求评估外部条件。
答案 2 :(得分:0)
如果您愿意引入导航属性Foo.Bar1
和Foo.Bar2
,则可以非常简单。然后你可以这样做:
from f in Foos
select new { f, f.Bar1, f.Bar2 }
这将在SQL中创建外连接。 (这可能是不喜欢这些导航属性的原因,因为很容易忘记它们会导致外连接,如果没有它们,你总是被要求自己控制)。