IQueryable<T>批量获取数据的扩展方法

问题描述 投票:0回答:3

有人找到/编码了批量查询数据(使用linq to sql)的扩展方法吗?我见过 IEnumerable 扩展,但我正在寻找我可能会使用的东西,如下所示:

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
   }
}
c# .net linq-to-sql
3个回答
11
投票

你能做的是:

public static IEnumerable<T[]> InBatches<T>(this IQueryable<T> collection, int size)
{
    List<T> batch = new List<T>(size);

    foreach (T item in collection)
    {
        if (batch.Count == size)
        {
            yield return batch.ToArray();
            batch.Clear();
        }

        batch.Add(item);
    }

    if (batch.Count > 0) yield return batch.ToArray();
}

此扩展方法循环遍历 IQueryable 一次(即对数据库的一次查询),并以流方式将批次吐出为数组。通过流式传输结果,它只允许将数据的子集保留在内存中(这对于非常大的数据集来说很有趣)。

用途:

IQueryable<Order> orders = from order in db.Orders select order;
foreach (Order[] batch in orders.InBatches(size: 100))
{
   // Batch of 100 products
   foreach(Order order in batch)
   {
      //do something
   }
}

2
投票

Take
Skip
有什么问题吗?这些是 LINQ 运算符,用于从
IEnumerable<T>
IQueryable<T>
(及其非通用对应项)获取批次。


1
投票

如果您不关心批次本身,而只想出于大小或事务目的断开连接,则可以执行以下操作:

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);
}
© www.soinside.com 2019 - 2024. All rights reserved.