0

我在一個小的.NET 4.5,MVC4,EF5項目上使用了存儲庫模式。存儲庫模式和IQueryable <>生成不好的SQL

我注意到,如果我改變了從存儲庫傳遞的IQueryable對象的結果,生成的SQL並不理想。

例如,在我的倉庫:

public IQueryable<Entry> GetEntries() 
    { 
     // (db is an instance of the data context) 
     return db.Entries.Where(e => e.UserId == WebSecurity.CurrentUserId); 
    } 

在我的控制器,我限制行的金額退回,並對其進行排序:

public ActionResult Index() 
    { 
     // (repo is an instance of the repository object) 
     var entries = repo.GetEntries().Take(10).OrderByDescending(o => o.Created) 
     return View(entries); 
    } 

這將生成以下SQL:

DECLARE @p__linq__0 int = 1 

SELECT 
[Project1].[UserId] AS [UserId], 
[Project1].[Id] AS [Id], 
[Project1].[Created] AS [Created], 
[Project1].[LastModified] AS [LastModified], 
[Project1].[BodyOriginal] AS [BodyOriginal], 
[Project1].[BodyFormatted] AS [BodyFormatted], 
[Project1].[FormatterVersion] AS [FormatterVersion], 
[Project1].[BodyDigest] AS [BodyDigest], 
[Project1].[FollowupId] AS [FollowupId], 
[Project1].[AddMethod] AS [AddMethod], 
[Project1].[Entry_Id] AS [Entry_Id] 
FROM (SELECT 
     [Extent1].[Id] AS [Id], 
     [Extent1].[UserId] AS [UserId], 
     [Extent1].[Created] AS [Created], 
     [Extent1].[LastModified] AS [LastModified], 
     [Extent1].[BodyOriginal] AS [BodyOriginal], 
     [Extent1].[BodyFormatted] AS [BodyFormatted], 
     [Extent1].[FormatterVersion] AS [FormatterVersion], 
     [Extent1].[BodyDigest] AS [BodyDigest], 
     [Extent1].[FollowupId] AS [FollowupId], 
     [Extent1].[AddMethod] AS [AddMethod], 
     [Extent1].[Entry_Id] AS [Entry_Id] 
     FROM [dbo].[Entries] AS [Extent1] 
     WHERE [Extent1].[UserId] = @p__linq__0 
) AS [Project1] 
ORDER BY [Project1].[Created] DESC 

如您所見,生成的SQL高度冗餘。

如果我修改資料庫的方法包括截斷和排序結果:

public IQueryable<Entry> GetEntries() 
    { 
     // (db is an instance of the data context) 
     return db.Entries.Where(e => e.UserId == WebSecurity.CurrentUserId).Take(10).OrderByDescending(o => o.Created); 
    } 

生成的SQL是更好:

DECLARE @p__linq__0 int = 1 

SELECT 
      [Extent1].[Id] AS [Id], 
      [Extent1].[UserId] AS [UserId], 
      [Extent1].[Created] AS [Created], 
      [Extent1].[LastModified] AS [LastModified], 
      [Extent1].[BodyOriginal] AS [BodyOriginal], 
      [Extent1].[BodyFormatted] AS [BodyFormatted], 
      [Extent1].[FormatterVersion] AS [FormatterVersion], 
      [Extent1].[BodyDigest] AS [BodyDigest], 
      [Extent1].[FollowupId] AS [FollowupId], 
      [Extent1].[AddMethod] AS [AddMethod], 
      [Extent1].[Entry_Id] AS [Entry_Id] 
      FROM [dbo].[Entries] AS [Extent1] 
      WHERE [Extent1].[UserId] = @p__linq__0 
    ORDER BY [Extent1].[Created] DESC 

如何克服這個問題,那就是使用存儲庫模式,同時仍然可以靈活地修改存儲庫的結果而不會創建構造不佳的SQL?

+1

在這種情況下,冗餘不會影響性能。 – usr

+1

我不認爲你顯示了相同的查詢。注意第二個查詢沒有Order by子句。這似乎表明它實際上並沒有做同樣的事情。 –

+0

如果它們是相同的,那麼這意味着Linq可能通過在內存中而不是在SQL中執行Take和OrderBy來優化第二個查詢,這可能是因爲它可以「看到」更多的內容。儘管我不能某些。 –

回答

1

這是存儲庫反模式,最好刪除'存儲庫'。如果您真的想使用Repository,請定義一個與EF無關的接口,並且不返回IQueryable。此外,是否使用存儲庫與EF如何生成sql無關。