2012-07-23 71 views
8

用下面的表結構(刪除多餘的欄)包括和Where謂詞事業左連接,而不是內部聯接

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到實體查詢:

// 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%') 

爲什麼在第三查詢,它生成一個第二次在Events表上顯示0?雖然查詢產生正確的結果,但它似乎很奇怪,爲什麼EF/LINQ爲什麼不能在SELECTWHERE子句中重複使用[Extent2],爲什麼它是LEFT OUTER JOIN

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

回答

6

在捐贈指向不存在的事件的情況下,左連接將確保Donations表中沒有行缺失。他們不希望Include關鍵字具有導致原始表中缺少行的副作用,因此他們必須使用左連接來確保安全。

關於包含表格兩次,這可能只是EF的限制。您在查詢中提及了兩次,並且它不夠聰明,無法進行優化。

我不得不說,如果你想優化SQL然後編寫SQL,不要打擾EF。你在做什麼可以與反編譯C#和詢問爲什麼彙編器沒有特定的優化。如果你使用EF然後閉上你的眼睛,哪些SQL它產生:-)

+1

第二個查詢使用'Include',但不會產生左連接。 – Matthew 2012-07-23 04:53:37

+0

非常好的問題,我沒有注意到。這似乎對我來說很重要。第二個查詢應該有一個左連接,以便Include不會導致副作用,第三個查詢應該有內連接,因爲它無論如何都需要一個事件行。 – MikeKulls 2012-07-23 05:56:02

+0

如果左連接是可爲空的列,或者如果我沒有參照完整性,則左連接將有意義。 – Matthew 2012-07-23 14:38:15

0

不直接回答你的問題,而是企圖閱讀您的意見對其他的答案後,你指出正確的方向:

你擁有一切你需要的東西來保護一些ORM消息(包括EF) - 這就是你說的SP的數量和質量。任何方法都會有問題,包括純sql,如果這個sql寫得不好或難以維護。因此,如果某些ORM(EF等)有時會產生非高效的代碼,並且這確實會導致性能問題,那麼即使使用SP,這也會成爲「需求」並需要解決。

因此,從商業角度來看你的問題 - 你的結構不好,很難維護一堆存儲過程。可能大部分你的團隊是C#而不是SQL開發人員。

使用ORM將增加代碼庫的可維護性,並且可以更好地利用C#中所有團隊成員的專業知識。

由ORM在某些特定場合生成的錯誤SQL代碼對於使用該技術幾乎是「不行」,除非證明它會產生比解決現有問題更多的問題。

+0

我會看看另一種方式。如果開發人員對sql不熟悉,那麼他們需要變得有經驗。畢竟他們正在編寫數據庫應用程序,而現在缺乏sql知識是不可接受的。他們*不需要的一件事是避免sql的更多原因。 – MikeKulls 2012-08-01 22:58:31

+0

他們絕對不是SQL經驗不足,應用程序經歷了9年的不斷開發(從ASP.net 1.0開始),許多不同的開發人員。目前的應用程序沒有關注問題,直接在代碼中調用存儲過程。這就是爲什麼我正在尋找一些易於管理的東西,主要是因爲我認爲現在存儲的procs的組織是一個註銷。 – Matthew 2012-08-02 02:13:53