2011-12-08 9 views
13

Poniższy kod:Pomiń i podejmij: Skuteczne podejście do LIMITU PRZESUNIĘCIE w EF 4.1?

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

wygeneruje następujący 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 */ 

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

NB Skip i Take nie zostały przetłumaczone na SQL powodując Wszystkie Posty z bloga ładowanego z bazy danych, zamiast tylko 5, których potrzebujemy.

Wydaje się to niebezpiecznie, potwornie nieefektywne. Niewiarygodne, co daje?

Odpowiedz

19

Powód to się dzieje jest wezwanie do First, co jest przyczyną przedmiotem Blog być zrealizowana. Każde dalsze przejście wymaga więcej pytań.

Wypróbuj db.Blogs.Take(1).SelectMany(b => b.Posts).Skip(10).Take(5).ToList(); zamiast tego w jednym zapytaniu. Prawdopodobnie chcesz dodać jakieś uporządkowanie blogów przed .Take(1), aby zapewnić deterministyczny wynik.

Edit rzeczywiście trzeba używać orderby przed SKIP (inaczej LINQ do podmiotów rzuci wyjątek), co sprawia, że ​​jest coś takiego:

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

Jak sugeruje w swoim poście, zamiast tego można użyć EQL do wykonania tego zapytania. Coś jak:

// 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); 

Kodeksu podjętej stąd: http://msdn.microsoft.com/en-us/library/bb738702.aspx

+0

Dzięki za odpowiedź, która jest pomocna, ale szukałem rozwiązania wolnego od EQL. Powinienem to stwierdzić w pytaniu. W każdym razie dzięki. – Tom

1

Można próbować uzyskać swój pierwszy blog i wykorzystanie identyfikator bloga do filtrowania takich postów:

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

Dziękuję coonooo. – Tom

Powiązane problemy