0

我编写了一个 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 选择)

4

3 回答 3

0

如以下链接所示,LINQ仅支持 support equal。如果您需要任何其他类型的连接,请使用交叉连接,其中:

Linq - 在多个(OR)条件下左连接

于 2012-09-27T13:07:12.630 回答
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 };

我怀疑这只会给你一个内连接而不是外连接,你可能需要为 !Contains 添加另一个 where 子句,以根据你的要求评估外部条件。

于 2012-09-27T13:48:39.190 回答
0

如果您愿意引入导航属性Foo.Bar1Foo.Bar2. 然后你可以这样做:

from f in Foos
select new { f, f.Bar1, f.Bar2 }

这将在 SQL 中创建外连接。(这可能是不喜欢这些导航属性的一个原因,因为很容易忘记它们会导致外部连接,没有它们你总是被敦促自己控制)。

于 2012-09-28T15:01:03.473 回答