2011-12-08 69 views
13

下面的代碼:跳過並採取:EF 4.1中的OFFSET LIMIT的有效方法?

using (var db = new Entities()) 
{ 
    db.Blogs.First().Posts.Skip(10).Take(5).ToList(); 
} 

將生成以下SQL:

-- statement #1 
SELECT TOP (1) [c].[Id] AS [Id], 
      [c].[Title]   AS [Title], 
      [c].[Subtitle]  AS [Subtitle], 
      [c].[AllowsComments] AS [AllowsComments], 
      [c].[CreatedAt]  AS [CreatedAt] 
FROM [dbo].[Blogs] AS [c] 

-- statement #2 
SELECT [Extent1].[Id] AS [Id], 
    [Extent1].[Title] AS [Title], 
    [Extent1].[Text]  AS [Text], 
    [Extent1].[PostedAt] AS [PostedAt], 
    [Extent1].[BlogId] AS [BlogId], 
    [Extent1].[UserId] AS [UserId] 
FROM [dbo].[Posts] AS [Extent1] 
WHERE [Extent1].[BlogId] = 1 /* @EntityKeyValue1 */ 

(從http://ayende.com/blog/4351/nhibernate-vs-entity-framework-4-0

NB的跳躍和Take還沒有被翻譯成SQL導致所有職位從正在從數據庫加載的博客中,而不是我們需要的5個。

這看起來很危險,可怕的效率很低。令人難以置信的是,是什麼給了?

回答

19

它的發生原因是調用First,這是造成Blog對象被物化。任何進一步的遍歷都需要更多的查詢。

嘗試db.Blogs.Take(1).SelectMany(b => b.Posts).Skip(10).Take(5).ToList();而不是在一個查詢中完成。您可能希望在.Take(1)之前添加某種博客排序,以確保確定性結果。

編輯 你確實有跳過前使用排序依據(否則LINQ to實體會拋出異常),這使得它像:

db.Blogs.OrderBy(b => b.Id).Take(1) // Filter to a single blog (while remaining IQueryable) 
    .SelectMany(b => b.Posts) // Select the blog's posts 
    .OrderBy(p => p.PublishedDate).Skip(10).Take(5).ToList(); // Filter to the correct page of posts 
2

正如他在他的文章中所建議的,您可以使用EQL來執行此查詢。喜歡的東西:從這裏取

// Create a query that takes two parameters. 
string queryString = 
    @"SELECT VALUE product FROM 
     AdventureWorksEntities.Products AS product 
     order by product.ListPrice SKIP @skip LIMIT @limit"; 

ObjectQuery<Product> productQuery = 
    new ObjectQuery<Product>(queryString, context); 

// Add parameters to the collection. 
productQuery.Parameters.Add(new ObjectParameter("skip", 3)); 
productQuery.Parameters.Add(new ObjectParameter("limit", 5)); 

// Iterate through the collection of Contact items. 
foreach (Product result in productQuery) 
    Console.WriteLine("ID: {0}; Name: {1}", 
    result.ProductID, result.Name); 

代碼:http://msdn.microsoft.com/en-us/library/bb738702.aspx

+0

感謝您的回答,這是有幫助的,但我一直在尋找一個無EQL解決方案。我應該在問題中說明這一點。不過謝謝。 – Tom

1

你可以嘗試讓你的第一個博客和使用博客ID來過濾這樣的帖子:

Blog blog=db.Blogs.first(); 
blog.posts=Posts.Where(r=>r.blogID=blog.id).Skip(10).Take(5).ToList(); 
+0

謝謝coonooo。 – Tom