2011-11-09 26 views
5

Có phương pháp mở rộng được tìm thấy/mã hóa nào truy vấn dữ liệu (sử dụng LINQ đến sql) theo lô không? Tôi đã nhìn thấy phần mở rộng IEnumerable nhưng tôi đang tìm kiếm cái gì tôi có thể sử dụng như thế này:IQueryable <T> Phương pháp mở rộng để lấy dữ liệu theo lô

IQueryable<Order> orders = from i in db.Orders select i; 
foreach(var batch in orders.InBatches(100)) 
{ 
    //batch of 100 products 
    foreach(var order in batch) 
    { 
     //do something 
    } 
} 
+1

Bạn có chắc chắn muốn sử dụng Linq-2-sql cho các lô. Nói chung, nó không được thiết kế để làm điều đó. Ngay cả khi // của bạn làm điều gì đó sẽ đi theo lô và nó sẽ là bản cập nhật của một trường, bạn vẫn sẽ nhận được 100 báo cáo cập nhật riêng lẻ được gửi đến DB của bạn sau khi các thay đổi con. Tư vấn của tôi là trong trường hợp của bạn để sử dụng một thủ tục lưu trữ (và tôi là một fan Linq-2-sql bằng cách này) – Pleun

+0

cảm ơn nhưng mã của tôi chỉ truy vấn, không cập nhật – jlp

Trả lời

9

Những gì bạn có thể làm điều này là:

phương pháp
public static IEnumerable<IQueryable<T>> InBatches(
    this IQueryable<T> collection, int size) 
{ 
    int totalSize = collection.Count(); 

    for (int start = 0; start < totalSize; start += size) 
    { 
     yield return collection.Skip(start).Take(size); 
    } 
} 

Phần mở rộng này cho phép bạn làm bộ lọc thêm qua IQueryables trở lại. Tuy nhiên, tính hữu ích là khá hạn chế. Tôi không thể nghĩ ra bất kỳ kịch bản tốt cho điều này :-). Trong hầu hết các trường hợp, bạn chỉ muốn truyền các kết quả và trả lại một IEnumerable<IEnumerable<T>> sẽ chỉ làm tốt, và thậm chí còn tốt hơn, vì điều này sẽ dẫn đến một truy vấn SQL, trong khi cách tiếp cận được hiển thị sẽ dẫn đến các truy vấn N + 1.

+0

tin tôi trong kịch bản của mình tôi cần n + 1 truy vấn aproach – jlp

+1

Tuyệt vời: Tôi đã làm tốt trong ngày :-) – Steven

+2

Nó thực sự hữu ích khi bạn muốn thực hiện các thao tác trên tất cả các bản ghi của một bảng (ví dụ, bạn đã thêm một cột mới và trong sản xuất bạn muốn điền vào với giá trị thích hợp). Sau đó, bạn không muốn thực hiện một truy vấn duy nhất, để có được tất cả dữ liệu, vì nó có thể hết thời gian vì số lượng lớn. Do đó bạn thực hiện truy vấn theo lô và thực hiện cập nhật của mình theo nhiều bước hơn, nhưng không có thời gian chờ :) – Vlad

3

Có gì sai với TakeSkip? Đây là các toán tử LINQ để nhận các lô tắt IEnumerable<T> hoặc IQueryable<T> (và các đối tác không chung chung của chúng).

+1

không có gì ngoại trừ tôi cần đếm hồ sơ đầu tiên và sau đó làm cho vòng lặp . Tôi hỏi về phương pháp mở rộng mà tôi có thể tái sử dụng – jlp

1

Nếu bạn không quan tâm đến các lô bản thân và bạn chỉ muốn chia tay kết nối cho các mục đích kích thước hoặc giao dịch bạn có thể làm như sau:

public static IEnumerable<T> InBatches<T>(this IQueryable<T> collection, int batchSize) 
{ 
    int start = 0; 
    int records = 0; 
    IQueryable<T> batch; 

    // For the first batch 
    start -= batchSize; 

    do { 
     records = 0; 
     start += batchSize; 
     batch = collection.Skip(start).Take(batchSize); 

     foreach (T item in batch) { 

      records += 1; 
      yield return item; 
     } 

    } while (records == batchSize); 
} 
0

MoreLINQ mà là một thư viện tuyệt vời đi kèm với một loạt phương thức thực hiện chính xác điều đó.

https://github.com/morelinq/MoreLINQ

hàng loạt

lô nguồn chuỗi vào xô kích thước.

Phương pháp này có 2 quá tải.

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