Include和Where谓词导致左连接而不是内连接

时间:2012-07-23 03:16:15

标签: c# linq entity-framework linq-to-entities

使用以下表格结构(删除了无关列)

create table [Events]
(
    ID int not null identity,
    Name nvarchar(128) not null,
    constraint PK_Events primary key(ID)
)

create table [Donations]
(
    ID int not null identity,
    EventID int not null,
    Amount decimal(10, 2) not null,

    constraint PK_Donations primary key(ID),
    constraint FK_Donations_Events foreign key(EventID) references [Events](ID) on update no action on delete no action
)

我使用以下Linq-to-Entities查询:

// 1
ents.Donations.Where(d => d.Amount > 25.0m && d.Event.Name.Contains("Run")).ToList();

// 2
ents.Donations.Include("Event").Where(d => d.Amount > 25.0m).ToList();

// 3
ents.Donations.Include("Event").Where(d => d.Amount > 25.0m && d.Event.Name.Contains("Run")).ToList();

生成(来自SQL事件探查器):

-- 1
SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[EventID] AS [EventID], 
[Extent1].[Amount] AS [Amount]
FROM  [dbo].[Donations] AS [Extent1]
INNER JOIN [dbo].[Events] AS [Extent2] ON [Extent1].[EventID] = [Extent2].[ID]
WHERE ([Extent1].[Amount] > 25.0) AND ([Extent2].[Name] LIKE N'%Run%')

-- 2
SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[EventID] AS [EventID], 
[Extent1].[Amount] AS [Amount], 
[Extent2].[ID] AS [ID1], 
[Extent2].[Name] AS [Name]
FROM  [dbo].[Donations] AS [Extent1]
INNER JOIN [dbo].[Events] AS [Extent2] ON [Extent1].[EventID] = [Extent2].[ID]
WHERE [Extent1].[Amount] > 25.0

-- 3
SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[EventID] AS [EventID], 
[Extent1].[Amount] AS [Amount], 
[Extent3].[ID] AS [ID1], 
[Extent3].[Name] AS [Name]
FROM   [dbo].[Donations] AS [Extent1]
INNER JOIN [dbo].[Events] AS [Extent2] ON [Extent1].[EventID] = [Extent2].[ID]
LEFT OUTER JOIN [dbo].[Events] AS [Extent3] ON [Extent1].[EventID] = [Extent3].[ID]
WHERE ([Extent1].[Amount] > 25.0) AND ([Extent2].[Name] LIKE N'%Run%')

为什么在第3个查询中,它是否第二次在LEFT OUTER JOIN表上生成Events?虽然查询产生了正确的结果,但似乎很奇怪,为什么EF / LINQ不能在[Extent2]SELECT子句中重用WHERE,为什么它是LEFT OUTER JOIN

我正在使用Visual Studio 2010 sp1 .NET 4,我正在连接到Sql Server 2008 Express。

2 个答案:

答案 0 :(得分:7)

左边的连接是为了确保在捐赠指向不存在的事件的情况下Donations表中没有丢失任何行。他们不希望Include关键字产生副作用,导致原始表中缺少行,因此他们必须使用左连接才能确保安全。

关于将表格包括两次,这可能只是EF的限制。你在查询中提到了两次它并不够聪明,无法进行优化。

我不得不说如果你想优化SQL然后编写SQL,不要打扰EF。您正在做的事情可以与反编译C#进行比较,并询问汇编程序为什么没有某种优化。如果您使用EF,那么请关闭它产生的SQL: - )

答案 1 :(得分:0)

不是直接回答您的问题,而是在阅读完其他答案的评论后尝试指出正确的方向:

你拥有保护一些ORM消息所需的一切(包括EF) - 这就是你所说的关于SP的数量和质量的所有内容。任何方法都会遇到问题,包括纯sql,如果sql编写得不好或难以维护。

因此,如果某些ORM(EF等)有时产生无效的代码,这确实会导致性能问题,这就变成了“需求”,即使使用SP也需要解决。

因此,从业务角度看待您的问题 - 您的结构错误,难以维护大量存储过程。可能你的大多数团队都是C#而不是SQL开发人员。

使用ORM将提高代码库的可维护性,并且可以更好地利用C#中所有团队成员的专业知识。

ORM在某些特定情况下生成的错误SQL代码对于使用该技术来说几乎没有“禁止”,除非证明它会产生比解决现有技术更多的问题。