【问题标题】:Forcing linq to perform inner joins强制 linq 执行内部连接
【发布时间】:2011-11-23 13:30:28
【问题描述】:

我正在尝试强制 Linq 在两个表之间执行内部连接。我举个例子吧。

CREATE TABLE [dbo].[People] (
   [PersonId] [int] NOT NULL,
   [Name] [nvarchar](MAX) NOT NULL,
   [UpdatedDate] [smalldatetime] NOT NULL
   ... Other fields ...
)

CREATE TABLE [dbo].[CompanyPositions] (
   [CompanyPositionId] [int] NOT NULL,
   [CompanyId] [int] NOT NULL,
   [PersonId] [int] NOT NULL,
   ... Other fields ...
)

现在我正在使用不寻常的数据库,因为我无法控制人员从 People 表中丢失,但在 CompanyPositions 中有记录。我想通过加入表格来过滤掉缺少人员的 CompanyPositions。

return (from pos in CompanyPositions
        join p in People on pos.PersonId equals p.PersonId
        select pos).ToList();

Linq 认为此连接是多余的,并将其从它生成的 SQL 中删除。

SELECT 
[Extent1].[CompanyPositionId] AS [CompanyPositionId], 
[Extent1].[CompanyId] AS [CompanyId], 
.... 
FROM  [dbo].[CompanyPositions] AS [Extent1]

但是在我的情况下它并不是多余的。我可以这样修复它

// The min date check will always be true, here to force linq to perform the inner join
var minDate = DateTimeExtensions.SqlMinSmallDate;

return (from pos in CompanyPositions
        join p in People on pos.PersonId equals p.PersonId
        where p.UpdatedDate >= minDate
        select pos).ToList();

然而,这现在在我的 SQL 中创建了一个不必要的 where 子句。作为最纯粹的我想删除它。任何想法或当前的数据库设计是否束缚了我的双手?

【问题讨论】:

  • 你在用什么? LINQ到SQL? LINQ 到实体?还有什么?
  • 你的模型有导航属性吗?如果是这样,你可以写类似where pos.Person != null。
  • 我正在使用 LinqToSql,我尝试过 'where pos.Person != null' 和 'p.PersonId != 0' 并且 Linq 删除了它们。在 'p.PersonId != 0' 的情况下,它会将其更改为 'pos.PersonId != 0' 这给我留下了深刻的印象,即使这不是我所追求的。

标签: c# sql linq linq-to-sql


【解决方案1】:

由于 PersonId 被声明为 NOT NULL(并且我假设它被声明为 People 的 FK),那么我不确定您如何与未分配的人拥有 CompanyPosition;并且 Linq 看不到您如何 eiter,这就是为什么正如您所观察到的 Linq 认为连接是多余的。

【讨论】:

  • 这是有道理的,我正在使用的数据库是一个更大更复杂的主数据库的扁平化版本。只有与一种产品相关的数据会被转发到此,唉,由于缺少记录,因此没有 FK,这些都是在主服务器上强制执行的。在这种情况下,此人尚未发布,因此不会从主人那里推送。理想情况下,CompanyPosition 也不会,但这是我无法控制的。看起来数据库设计是这里的主要问题。
【解决方案2】:

如果你使用的是 LinqToSql,你可以使用类似这样的 LoadWith:

var context = new MyDataContext();
var options = new DataLoadOptions();
options.LoadWith<People>(x => x.CompanyPositions);
context.LoadOptions = options;

【讨论】:

    【解决方案3】:

    我不知道如何强制 linq 使用连接。但是下面的语句应该会给你所需的结果。

    return (from pos in CompanyPositions
            where (p in People select p.PersonId).Contains(pos.PersonId)
            select pos).ToList();
    

    【讨论】:

      【解决方案4】:

      客户端转换:

      (
      from pos in CompanyPositions
      join p in People on pos.PersonId equals p.PersonId
      select new {pos, p}
      ).ToList().Select(x => x.pos);
      

      更直接的过滤:

      from pos in CompanyPositions
      where pos.People.Any()
      select pos
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-04
        相关资源
        最近更新 更多