Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
或在多个列上进行Linq外部联接_Linq_Linq To Entities - Fatal编程技术网

或在多个列上进行Linq外部联接

或在多个列上进行Linq外部联接,linq,linq-to-entities,Linq,Linq To Entities,我编写了一个Linq查询来对多个列进行外部联接。我的问题是,我想删除或列。换句话说,我需要连接条件: on Bar.Id equals Foo.BarId1 or Bar.Id equals Foo.BarId2 我在这个网站上看到的一些例子使用匿名类型来创建和设置条件,但我不知道如何构造或使用匿名类型,或者是否可能。我找不到匹配的例子 我的问题是: var data = (from f in Foos join b in Bars on f.BarId

我编写了一个Linq查询来对多个列进行外部联接。我的问题是,我想删除或列。换句话说,我需要连接条件:

on Bar.Id equals Foo.BarId1 or Bar.Id equals Foo.BarId2
我在这个网站上看到的一些例子使用匿名类型来创建和设置条件,但我不知道如何构造或使用匿名类型,或者是否可能。我找不到匹配的例子

我的问题是:

    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指向有效条,而Foo.BarId2没有指向有效条时,它实际上会为Bar1和Bar2返回相同的条。在本例中,我希望Bar1有效,Bar2为null

编辑

我越来越近了。这是我的最新查询:

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选择,正如在下面的链接中一样,LINQ只支持equal。如果需要任何其他类型的联接,请使用交叉联接,其中:


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子句!包含根据您的要求评估外部条件。

如果您愿意引入导航属性Foo.Bar1和Foo.Bar2,则可以非常简单。然后你可以做:

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

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

这就是我正在做的,看看我的查询。哦,好的,但是你需要它做什么:把1等于1的条中的db连接到bs中,为什么不只做一个连接,像var data=from f in Foos from b in bar,其中f.Id==b.BarId1 | | f.Id==b.BarId2同样,我建议你看看这个工具:。。在测试Linq查询时,它真的很方便。这是一个公平的观点。我已经编辑了我的问题。但是,返回的结构是相同的。假设您有两个表:Foos Id BarId1 BarId2 10 1 NULL 20 NULL 2 bar Id Name 1'one'2'two,您得到的结果是正确的。嗯。。。你在这里遇到过LINQ限制吗?仅使用equals子句似乎没有什么可以做的。您没有或无法创建像Foo.Bar1和Foo.Bar2这样的导航属性?没有。可以为空的导航属性吗?@Gert Arnold。另外,通过这种方式,我可以更好地控制生成的查询。是的,您可以拥有可为空的,即非必需的导航属性。它们将在SQL中生成外部联接,因此新的{f,f.Bar1,f.Bar2}将是您所需要的全部。