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

Mat*_*hew 8 c# linq linq-to-entities entity-framework

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

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
)
Run Code Online (Sandbox Code Playgroud)

我使用以下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();
Run Code Online (Sandbox Code Playgroud)

生成(来自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%')
Run Code Online (Sandbox Code Playgroud)

为什么在第3次查询中,它是否第二次LEFT OUTER JOINEvents桌面上生成?虽然查询产生了正确的结果,但看起来很奇怪,为什么EF/LINQ不能[Extent2]SELECTWHERE子句中重复使用,为什么它是一个LEFT OUTER JOIN

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

Mik*_*lls 7

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

关于将表包括两次,这可能只是EF的限制.您在查询中提到了两次,并且进行优化并不够智能.

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