LINQ内存不足错误



我正在查询20万条记录,并耗尽了服务器的所有内存(这并不奇怪)。我是LINQ的新手,所以我发现了以下代码应该对我有帮助,但我不知道如何使用它:

public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> collection, int batchSize)
{
    List<T> nextbatch = new List<T>(batchSize);
    foreach (T item in collection)
    {
        nextbatch.Add(item);
        if (nextbatch.Count == batchSize)
        {
            yield return nextbatch;
            nextbatch = new List<T>(batchSize);
        }
    }
    if (nextbatch.Count > 0)
        yield return nextbatch;
}

来源:http://goo.gl/aQZIj

这是我的代码,它创建了"内存不足"错误。如何将新的Batch函数合并到代码中?

var crmMetrics = _crmDbContext.tpm_metricsSet.Where(a => a.ModifiedOn >= lastRunDate);
foreach (var crmMetric in crmMetrics)
{
    metric = new Metric();                                
    metric.ProductKey = crmMetric.tpm_Product.Id;
    dbContext.Metrics.Add(metric);
    dbContext.SaveChanges();
}

这是一个扩展方法,因此如果它是静态类的一部分,并且在代码中引用了该类的命名空间,则可以执行以下操作:

var crmMetricsBatches = _crmDbContext.tpm_metricsSet
                        .Where(a => a.ModifiedOn >= lastRunDate)
                        .AsEnumerable() // !!
                        .Batch(20);

但这无济于事。通过.AsEnumerable(),您仍然可以获取内存中的所有数据,但现在是20个数据块。这是因为您不能直接对IQueryable使用该方法:实体框架将尝试将其转换为SQL,但当然不知道如何做到这一点。

正如TGH所说,SkipTake更适合于此:

var crmMetricsPage = _crmDbContext.tpm_metricsSet
                        .Where(a => a.ModifiedOn >= lastRunDate)
                        .OrderBy(a => a.??) // some property you choose
                        .Skip(pageNo * pageSize)
                        .Take(pageSize);

其中pageNo0计数到您将需要的页数(- 1)。SkipTake表达式,EF知道如何将它们转换为SQL。EF需要OrderBy才能知道从哪里开始跳过。

在这个称为分页的过程中,您总是一次获得pageSize记录。查询的数量更多,但资源是多余的。一个条件是您可以提前确定pageSize。我不知道这是否符合你的逻辑。

如果不能使用分页,则应尝试缩小筛选器(Where(a => a.ModifiedOn >= lastRunDate),例如,尝试在一天或一周内分批获取数据。

我会使用Linq的Skip and Take来获取批次

看看这个:

http://www.c-sharpcorner.com/UploadFile/3d39b4/take-and-skip-operator-in-linq-to-sql/

相关内容

  • 没有找到相关文章

最新更新