【问题标题】:LINQ join on columns AND nullable variableLINQ 连接列和可为空的变量
【发布时间】:2013-02-21 23:59:04
【问题描述】:

我正在尝试使用 LINQ 通过匹配列来连接表,其中连接表中的列等于变量或变量为空(此时连接仍然需要在该字段上进行)。

我的 LINQ 类似于:

var data = (
    from lt in cxt.CmsPageRow
    join page in cxt.CmsPage on new { lt.CmsPageID, cmsSiteID.Value } equals new { page.CmsPageID, page.CmsSiteID }
    ...

cmsSiteID 是一个可为空的 INT。

我无法编译我的代码,因为它抱怨“在调用 'Join' 时类型推断失败。”

除此之外,我只需要在 cmsSiteID 不为空时加入 page.CmsSiteID。如果 cmsSiteID 为 null,则 lt.CmsPageID 上的连接仍然需要发生。

* 编辑 *

这个问题现在有点改变了。我可以通过在我的 LINQ 中的连接上使用 WHERE 子句来让它做我想做的事情。

join page in cxt.CmsPage.Where(p=>(cmsSiteID==0||p.CmsSiteID==cmsSiteID)) on lt.CmsPageID equals page.CmsPageID

但是,这仍然运行缓慢。如果我将传递的参数更改为文字,它会立即执行。

慢跑者

(@p__linq__1 = 0 OR [Extent2].[CmsSiteID] = @p__linq__1)

跑得快

(267 = 0 OR [Extent2].[CmsSiteID] = 267)

有没有办法加快速度?

【问题讨论】:

  • cmsSiteID 来自哪里?那是在别处声明的变量吗?
  • 您实际上是从page 中选择一些东西,还是纯粹为了知道从中提取多少项目而使用它?如果您从中选择一些东西,如果cmsSiteID 为空,您是否希望这些值为空?
  • cmsSiteID 是正在调用的执行 LINQ 的函数中的可为空参数。 cmsSiteID 不可能永远为空,除非我正在编辑现有代码,这些代码可能在其他地方具有不包含新添加的 cmsSiteID 参数的方法。
  • 那么如果有人提供了 CmsSiteId,它是否应该包含 CmsSiteId 为空的项目?

标签: c# sql linq


【解决方案1】:

join 在 LINQ 中采用内部连接(无空值)。尝试将 null 内容提取到单独的 where 子句中。我认为这些方面的内容应该适用于您所描述的内容。

from lt in cxt.CmsPageRow
join page in cxt.CmsPage on lt.CmsPageID == page.CmsPageID
where cmsSiteID == null || 
      (cmsSiteID != null && (page.CmsSiteID == null || page.CmsSiteId == cmsSiteID.Value))
select ...

更新

我没有意识到性能对你来说是个问题。在这种情况下,我建议根据运行时已知且不依赖于单个行的值创建不同的查询结构:

var rows = 
    from lt in cxt.CmsPageRow
    join page in cxt.CmsPage on lt.CmsPageID == page.CmsPageID
    select new {lt, page};
if (cmsSiteID != null)
{
    rows = rows.Where(r => r.page.CmsSiteID == null || 
                           r.page.CmsSiteId == cmsSiteID.Value));
}
var data = rows.Select(...);

此外,如果您的数据上下文设置正确,您应该能够使用导航属性在一定程度上简化您的代码。

var rows = ctx.CmsPageRow;
if (cmsSiteID != null)
{
    rows = rows.Where(r => r.CmsPage.Any(p => p.CmsSiteID == null || 
                               p.CmsSiteId == cmsSiteID.Value));
}
var data = rows.Select(...);

【讨论】:

  • 不幸的是,这将 SQL WHERE 子句放在了错误的位置。 LINQ 正在创建包含内部选择的 SQL,这是我需要 where 子句的地方(或直接在此内部选择中的内部连接上)。像您建议的那样对其进行编码保持当前的 6 秒执行,同时将 cmsSiteID 放在内部连接上,使其在不到 1/10 秒的时间内工作。这就是我想将它添加到 LINQ 的原因。
  • 现在变得更糟了。将其设置为变量似乎仍然非常缓慢。只有文字 INT 值似乎运行得很快。
  • 虽然这对我来说不能完全按照规定工作,因为我的示例中没有包含很多其他连接,但它确实让我朝着正确的方向前进。我在“var pageData = (cmsSiteID == 0) ? cxt.CmsPage : cxt.CmsPage.Where(p => (cmsSiteID != 0 && p.CmsSiteID == cmsSiteID));”的数据对象之前添加了一行以及“在 lt.CmsPageID 上的 pageData 中加入页面等于 page.CmsPageID”的连接,这很有效。
  • 兴趣点,并且几乎需要进行此更改,LINQ 生成的 SQL 使用上面列出的 SQL 运行速度非常慢。通过使用“pageData”对象,它消除了对“@p__linq__1 = 0 OR”代码的需求。这本身还不够,但 SQL 需要 "(@p__linq__1 0) AND " 才能真正发出嗡嗡声。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-07
  • 1970-01-01
  • 2013-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多