2012-02-10 9 views
12

Bir veritabanında saklanan makaleleri yayınlanma tarihini düşürerek sipariş vermeli ve ardından ilk 20 kaydı Id == 100 ile makaleden sonra almalıyım.Tüm listeyi önce belleğe yüklemeden SkipWhile Linq to Sql ile nasıl uygulanır?

IQueryable<Article> articles = 
    db.Articles 
    .OrderByDescending(a => a.PublicationDate) 
    .SkipWhile(a => a.Id != 100) 
    .Take(20); 

Ancak bu bir NotSupportedException üretir SkipWhile Sql (here bakınız) Linq desteklenmediği için:

Bu Linq ile yapmak istiyoruz şeydir.

Muhtemel bir çözüm sorguyu yürütmek ve sonra Nesne Linq to kullanılarak SkipWhile uygulamaktır:

IEnumerable<ArticleDescriptor> articles = 
    db.Articles 
    .OrderByDescending(a => a.PublicationDate) 
    .ToList() 
    .SkipWhile(a => a.Article.Id != 100) 
    .Take(20); 

Ama bu ilk belleğe bütün sıralı liste yüklemek ve daha sonra birinin ardından 20 maddesinde almak gerekir demektir Id == 100 ile.

Bu büyük bellek tüketiminden kaçınmanın bir yolu var mı?

Genel olarak, bunu SQL'de başarmanın en iyi yolu nedir?

+1

İlginç gereksinimi gibi deneyebilirsiniz. Id' ve 'PublicationDate' arasında herhangi bir ilişki var mı? Bunları tarihe göre sipariş etmek için gerçekten yapmak istediğin şey, "100" e ulaşana kadar o listeye devam et, ve sonra * gelecek 20'yi al. – AakashM

+0

Evet, tam olarak istediğim bu. Id' ve 'PublicationDate' arasında bir ilişki yoktur. Bu gerekçenin nedeni, sadece "Id" i bildiğim belirli bir makaleden sonra yayınlanmış belirli sayıda makaleyi almam gerektiğidir. Tabii ki, bu makalenin 'PublicationDate'ını bilseydim çok daha kolay olurdu. –

cevap

5

, iki ayrı sorgularda yapabilirsiniz:

  • Id == 100
  • ile Article arasında PublicationDate kurulması

    :
  • bu tarihten itibaren

şey gibi gelen 20 maddesinde Al

var articles = 
    db.Articles 
    .Where(a => a.PublicationDate 
      <= db.Articles.Single(aa => aa.Id == 100).PublicationDate) 
    .OrderByDescending(a => a.PublicationDate) 
    .Take(20); 

ama bunun için çok karmaşık olabilir:

var thresholdDate = db.Articles.Single(a => a.Id == 100).PublicationDate; 
var articles = 
    db.Articles 
    .Where(a => a.PublicationDate <= thresholdDate) 
    .OrderByDescending(a => a.PublicationDate) 
    .Take(20); 

Hatta LINQ to SQL bu tercüme olamayabilir. Deneyin ve gör.

+0

Bence bu, veritabanında saklı bir prosedüre de taşınabilecek iyi bir çözümdür (@Atzoya tarafından da yayınlanmıştır). Tek bir SQL sorgusu ile yapamayız sanırım.Buradaki tek sorun, (olası) etkinlikte, aynı anda yayınlanan farklı Ids ile birçok makaleye sahibiz. Fakat bunu çözmek için, makaleleri alırken ek bir sipariş kuralı üzerinde mutabık kalmamız gerekir. Örneğin, Ids: 'var makaleler = db.Articles .Where (a => a.PublicationDate <= thresholdDate && a. Id <100) .OrderByDescending (a => a.PublicationDate) .TenByDescending (a => a.Id) .Take (20); ' –

+0

Denedim ve çalışır. LINQ to SQL bile tüm LINQ sorgusunu tek bir SQL sorgusuna çevirmeyi bile yönetir. –

+0

Tek (a => a.Id == 100) Single (aa => aa.Id == 100) ile değiştirilmenizi önerebilir miyim? –

0

Çözüm, yalnızca bir ifade ekleyemez mi? Ben sütun adından tahmin ediyorum gibi PublicationDate değişmez ise

IQueryable<Article> articles = db.Articles.Where(a => a.id != 100).OrderByDescending(a => a.PublicationDate).Take(20); 
+0

Evet, ben de düşündüm, ama asıl şartlara bak: onları tarihe göre sırala, 100, ** o zamana kadar sıradaki listeye gir, sonra sıradaki 20'yi al. – AakashM

+1

Eğer makale 5 yayınlandıysa bu işe yaramayacaktır _after_ madde 10 (örneğin taslakta oturduğunuz için) –

+0

Evet, soruyu çok özledim. – Tan

1

Bu

var articles = 
    db.Articles 
    .Where(a => a.PublicationDate < db.Articles 
            .Where(aa => aa.Id==100) 
            .Select(aa => aa.PublicationDate) 
            .SingleOrDefault()) 
    .OrderByDescending(a => a.PublicationDate) 
    .Take(20); 
+0

+1, bu AakashM tarafından yayınlanan ile aynı çözümdür, ancak diğerinin daha açık bir açıklaması vardır. –