2012-02-10 18 views
12

Tôi cần đặt hàng các bài viết được lưu trữ trong cơ sở dữ liệu theo ngày xuất bản giảm dần và sau đó lấy 20 bản ghi đầu tiên sau bài viết với Id == 100.Làm thế nào để thực hiện SkipWhile với LINQ to Sql mà không cần tải toàn bộ danh sách vào bộ nhớ?

Đây là những gì tôi muốn làm với LINQ:

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

Tuy nhiên, điều này tạo ra một NotSupportedException vì SkipWhile không được hỗ trợ trong LINQ to SQL (xem here).

Một giải pháp khả thi là để thực hiện truy vấn và sau đó áp dụng SkipWhile sử dụng LINQ to Object:

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

Nhưng điều này có nghĩa là tôi cần phải tải toàn bộ danh sách lệnh vào bộ nhớ đầu tiên và sau đó lấy 20 bài viết sau một trong những với Id == 100.

Có cách nào để tránh mức tiêu thụ bộ nhớ khổng lồ này không?

Nói chung, cách tốt nhất để đạt được điều này trong SQL là gì?

+1

yêu cầu Thú vị này. Có mối quan hệ nào giữa 'Id' và' PublicationDate' không? Là những gì bạn muốn làm thực sự để đặt chúng theo ngày, đi dọc theo danh sách đó cho đến khi bạn nhận được để 'Id'' 100', và * sau đó * mất 20 tiếp theo? – AakashM

+0

Vâng, đó là chính xác những gì tôi muốn. Không có mối quan hệ nào giữa 'Id' và' PublicationDate'. Lý do cho yêu cầu này là tôi cần tìm nạp một số bài báo nhất định được xuất bản sau một bài viết cụ thể mà tôi chỉ biết 'Id'. Tất nhiên, nếu tôi biết 'PublicationDate' của bài viết đó, nó sẽ dễ dàng hơn nhiều. –

Trả lời

5

Nếu, như tôi đoán từ tên cột, PublicationDate không thay đổi, bạn có thể làm điều này trong hai truy vấn riêng biệt:

  • Thiết lập PublicationDate của Article với Id == 100
  • Truy lục 20 bài viết từ ngày đó trở đi

Một cái gì đó như:

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

Nó thậm chí có thể là LINQ to SQL có thể dịch này:

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

nhưng điều đó có thể quá phức tạp đối với nó. Hãy thử nó và xem.

+0

Tôi nghĩ rằng đây là một giải pháp tốt (cũng được đăng bởi @Atzoya), cũng có thể được chuyển đến một thủ tục được lưu trữ trong cơ sở dữ liệu. Tôi cho rằng chúng ta không thể làm điều đó với một truy vấn SQL đơn lẻ.Vấn đề duy nhất ở đây là trong sự kiện (không chắc) chúng tôi có nhiều bài viết với các Id khác nhau được đăng cùng một lúc. Nhưng để sắp xếp điều này, chúng tôi cần phải đồng ý về quy tắc đặt hàng bổ sung khi tìm nạp các bài viết, như bằng cách giảm dần các Id: 'var articles = db.Articles .Where (a => a.PublicationDate <= thresholdDate && a. Id <100) .OrderByDescending (a => a.PublicationDate) .ThenByDescending (a => a.Id) .Take (20); ' –

+0

Tôi đã thử và nó hoạt động. LINQ to SQL thậm chí còn quản lý để dịch toàn bộ truy vấn LINQ thành một truy vấn SQL đơn. –

+0

Tôi đề nghị bạn thay thế Single (a => a.Id == 100) bằng Single (aa => aa.Id == 100) để chấp nhận câu trả lời này? –

0

Không phải là giải pháp để thêm câu lệnh ở đâu?

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

Vâng tôi cũng nghĩ vậy, nhưng hãy nhìn vào yêu cầu thực tế: sắp xếp chúng theo ngày, đi dọc theo danh sách đó cho đến khi bạn nhận được id 100, ** sau đó ** lấy 20 giây tiếp theo. – AakashM

+1

Điều này sẽ không hoạt động nếu bài viết 5 đã được xuất bản _after_ điều 10 (do ngồi trong dự thảo ví dụ) –

+0

Vâng tôi đã hiểu sai câu hỏi. – Tan

1

Bạn có thể thử như

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 vì đây là giải pháp giống như giải pháp được đăng bởi AakashM, nhưng giải pháp khác có giải thích rõ ràng hơn –

Các vấn đề liên quan