【问题标题】:multiple join on conditions sql to linq多个连接条件 sql to linq
【发布时间】:2016-04-08 14:28:10
【问题描述】:

如何将下面的 sql 更改为 linq。

select distinct * from dbo.TbleA a
left outer join dbo.TbleB b on a.schid = b.schid
left outer join dbo.TbleC c on b.addrid=c.addrid
and c.userid=a.userid
where b.addrid=1 

这是导致错误的我的 linq 版本:

from a in db.TbleA
join b in db.TbleB on a.schid equals b.schid
join c in db.TbleC on new { w = b.addrid, z = a.userid } equals new { w=(int?)c.addrid, z=c.userid}
where (b.addrid == 1)

我在这里遇到错误:

在新的 { w = b.addrid, z = a.userid } 上加入 db.TbleC 中的 c 等于新 { w=(int?)c.addrid, z=c.userid}

我确实知道问题出在哪里,我要与我的联接中的两个表进行比较。 谢谢,错误是:

"join 子句中的表达式之一的类型不正确""调用 join 时类型推断失败"

b.addrid - int, 
a.userid - string, 
c.addrid - int?
c.userid - string

【问题讨论】:

  • 请准确说出错误是什么——当我们看不到问题时,很难提供帮助。
  • 您的 sql 查询不清楚:如果您在 TbleB 上使用 left join 并在 tbleB 上使用 Where 子句,就好像您在进行内部连接一样。你想要左连接还是内连接?顺便说一句,为什么要强制转换为 int? b.addrid 和 c.addrid 不是同一类型?
  • @JonSkeet 它说连接类型不正确,我想我也提到了错误在哪里。如果您仔细查看我的 linq,我确实知道问题出在哪里。查看我的更新。
  • @RaphaëlAlthaus 我转换为接受在 linq 中正确的空值。那么 linq 中的内部连接又是什么?
  • 对,所以在未来,正确的做法是在问题中包含 full 错误消息。我建议您将其与我询问的其他信息一起编辑...

标签: c# linq


【解决方案1】:

在不知道所涉及的类型的情况下,我们无法真正判断当前查询在编译方面有什么问题,但无论如何它都不等同于您的原始 SQL,因为您需要左外连接。我怀疑你想要更多类似的东西:

from a in db.TbleA
join b in db.TbleB on a.schid equals b.schid into bs
from b in bs.DefaultIfEmpty()
join c in db.TbleC on new { w = (int?)b?.addrid, z = a.userid }
               equals new { w = c.addrid, z = c.userid } into cs
from c in cs.DefaultIfEmpty()
where (b.addrid == 1)

当然,前提是您可以将 C# 6 与 null 条件运算符一起使用。如果没有,您至少逻辑上需要:

from a in db.TbleA
join b in db.TbleB on a.schid equals b.schid into bs
from b in bs.DefaultIfEmpty()
join c in db.TbleC on new { w = (b == null ? default(int?) : (int?)b.addrid), z = a.userid }
               equals new { w = c.addrid, z = c.userid } into cs
from c in cs.DefaultIfEmpty()
where b == null || b.addrid == 1

【讨论】:

  • @RaphaëlAlthaus:很好的收获 - 已添加。
  • @JonSkeet 我收到此错误“转换为值类型'System.Int32'失败,因为具体化值为空。结果类型的通用参数或查询必须使用可为空的类型。 "
  • @Menew:不幸的是,很难远程诊断出问题所在。我建议您尝试将其减少到展示问题的绝对最小查询,然后提出一个新问题 - 尽管我怀疑在将其减少到最小查询的过程中,您将能够解决问题。跨度>
【解决方案2】:

我怀疑您的错误是由于尝试比较不同类型的 LinQ 语句中的匿名类引起的。我建议您将联接更改为以下内容:

from a in db.TbleA
join b in db.TbleB on a.schid equals b.schid
join c in db.TbleC on new { w = (int?)b.addrid, z = a.userid } equals new { w=(int?)c.addrid, z=c.userid}
where (b.addrid == 1)

【讨论】:

  • 在连接中使用匿名类型绝对没问题。
  • 我的错。那里有点太快了。我只将它用于letselect 并且无法想象它们可以用于equals。
  • 这仍然不等同于原始查询。
  • 这有效并消除了错误,所以我添加了 int?比较
  • 我建议您查看正在生成的 SQL - 我强烈怀疑它不是您想要的,因为它不是左外连接。
猜你喜欢
  • 2011-12-07
  • 1970-01-01
  • 2010-11-10
  • 1970-01-01
  • 1970-01-01
  • 2011-01-10
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多