Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.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
C# Linq-多(或)条件下的左连接_C#_Linq To Sql - Fatal编程技术网

C# Linq-多(或)条件下的左连接

C# Linq-多(或)条件下的左连接,c#,linq-to-sql,C#,Linq To Sql,我需要在多个条件下执行左连接,其中条件是或s,而不是和s。我已经找到了很多关于后者的例子,但是我正在努力为我的场景找到正确的答案 from a in tablea join b in tableb on new { a.col1, a.col2 } equals new { b.col1, b.col2 } group a by a into g select new () { col1 = a.col1, col2 = a.col2, count = g.Count() } 适用于所有条件都

我需要在多个条件下执行左连接,其中条件是
s,而不是
s。我已经找到了很多关于后者的例子,但是我正在努力为我的场景找到正确的答案

from a in tablea
join b in tableb on new { a.col1, a.col2 } equals new { b.col1, b.col2 }
group a by a into g
select new () { col1 = a.col1, col2 = a.col2, count = g.Count() }
适用于所有条件都必须匹配的联接。我需要使连接与a.col1=b.col1或a.col2=b.col2上的
匹配

我知道这一定很容易,但我对此一无所知

编辑:

为了提供更多信息,查询的目的是获取一个投影,该投影包含“a”中的所有字段以及“b”中的匹配记录计数。我已经修改了上面的示例,试图说明我所追求的。当我使用Jon Skeet指出的方法运行上面的代码时,我得到的是a中所有记录的计数,而不是b中相关记录的计数

基本的左连接工作正常:

from a in tablea
from b in tableb
.Where( b => ( a.col1 == b.col1 || a.col2 == b.col2))
.DefaultIfEmpty()
select new { col1 = a.col1, col2 = a.col2 }
如果我修改它以添加如下分组

from a in tablea
from b in tableb
.Where( b => ( a.col1 == b.col1 || a.col2 == b.col2))
.DefaultIfEmpty()
group a by a.col1 into g
select new { col1 = g.Key, count = g.Count() }
我得到的是从a返回的记录数,而不是b中匹配的记录数

编辑:

我会给Jon答案-我已经解决了我的计数问题-我没有意识到我可以使用lamda来过滤计数
(g.count(x=>x!=null))
。另外,我需要按a分组b,而不是按a分组,正如我上面所说的那样。这给出了正确的结果,但是SQL并不像我手工编写的那样高效,因为它添加了一个相关的子查询-如果有人能建议一种更好的编写方法来模拟下面的SQL,我将不胜感激

select a.col1, count(b.col1)
from tablea a
left join tableb b
on a.col1 = b.col1
or a.col2 = b.col2
group by a.col1

LINQ仅直接支持Equijoin。如果要进行任何其他类型的联接,基本上需要交叉联接和
其中

from a in tablea
from b in tableb
where a.col1 == b.col1 || a.col2 == b.col2
select ...

可能值得检查生成的SQL是什么样子以及查询计划是什么样子。可能有更有效的方法,但这可能是最简单的方法。

根据查询提供程序的不同,您可以选择使用两个from子句:

from a in tablea
from b in tableb 
where a.col1 == b.col1 || a.col2 == b.col2
如果在DB上执行,它的效率同样高。如果在内存中执行(Linq到对象),这将枚举所有可能的组合,这可能会导致效率低下

Arg,带骨架;-)

更有效的Linq对象替代方案是可能的。
join
操作符只枚举每个源一次,然后进行散列联接,因此可以将or子句拆分为两个单独的联接,然后进行它们的并集。linq中的并集只是一个没有重复项的串联,因此如下所示:

(from a in tablea
join b in tableb on a.Col1 equals b.Col1
select new {a, b})
.Concat(
from a in tablea
join b in tableb on a.Col2 equals b.Col2
select new {a, b}
).Distinct()
var bBy1 = tableb.ToLookup(b=>b.Col1);
var bBy2 = tableb.ToLookup(b=>b.Col2);
var q3 = 
    from a in tablea
    from b in bBy1[a.Col1].Concat(bBy2[a.Col2]).Distinct()
    ...
这种方法是有效的,它只是一个查询,但代码的性能特征取决于对linq工作原理的详细理解,这在某种意义上是不明显的。就个人而言,如果您想使用可能的多个匹配项进行哈希连接,一个更明显的工具是
ToLookup
。另一种使用的方法可能如下所示:

(from a in tablea
join b in tableb on a.Col1 equals b.Col1
select new {a, b})
.Concat(
from a in tablea
join b in tableb on a.Col2 equals b.Col2
select new {a, b}
).Distinct()
var bBy1 = tableb.ToLookup(b=>b.Col1);
var bBy2 = tableb.ToLookup(b=>b.Col2);
var q3 = 
    from a in tablea
    from b in bBy1[a.Col1].Concat(bBy2[a.Col2]).Distinct()
    ...

这个解决方案实际上比较短,而且它起作用的原因更加明显,所以我更喜欢它。请记住,如果您将
|
操作符拆分为两个独立的查询,就像在上述两个场景中一样,您需要手动避免重复计算结果(即使用
Distinct
)。

我从这种方法开始。。。实际上,我正在对查询进行分组,以从a中获取所有记录,并从b中获取匹配记录的计数。我将编辑这篇文章以澄清问题。我建议你在不分组的情况下尝试我的查询,看看是否能得到你期望的结果。如果是这样,那么试着找出分组失败的原因。也许group by
new{a.col1,a.col2}
?作为一个基本的左连接选择可以很好地工作-如果这是一个基本的equi连接,那么从分组中获取计数的行为并不像我预期的那样。请注意上面的额外信息。我正在使用Linq访问对象-是否有其他解决方案?