使用IEnumerable <t>和Linq-To-Sql时如何防止内存溢出?</t>

时间:2009-06-23 18:51:10

标签: c# .net linq-to-sql ienumerable yield

此问题与a previous question of mine

有关

这是我目前的代码

 IEnumerable<Shape> Get()
 {
     while(//get implementation
         yield return new Shape(//...
 }

 void Insert()
 {
       var actual = Get();
       using (var db = new DataClassesDataContext())
       {
           db.Shapes.InsertAllOnSubmit(actual);
           db.SubmitChanges();
       }
 }

我的内存溢出,因为IEnumerable太大了。我该如何预防?

4 个答案:

答案 0 :(得分:3)

一种选择是将其分成多个批次。创建Shape个对象的临时缓冲区,迭代直到填充或从枚举器中用完,然后执行InsertBatchOnSubmit

答案 1 :(得分:3)

尝试使用InsertOnSubmit而不是InsertAllOnSubmit。然后像Erich说的那样以适当的间隔提交。

或者,如果你想分批进行,例如5,尝试Handcraftsman'sdtb's解决方案获取IEnumerable的IEnumerable。例如,使用dtb的Chunk:

   var actual = Get();
   using (var db = new DataClassesDataContext())
   {
       foreach(var batch in actual.Chunk(5))
       {
         db.Shapes.InsertAllOnSubmit(batch);
         db.SubmitChanges();
       }
   }

答案 2 :(得分:2)

使用以下扩展方法将输入分解为适当大小的子集

public static class IEnumerableExtensions
{
    public static IEnumerable<List<T>> InSetsOf<T>(this IEnumerable<T> source, int max)
    {
        List<T> toReturn = new List<T>();
        foreach(var item in source)
        {
            toReturn.Add(item);
            if (toReturn.Count == max)
            {
                yield return toReturn;
                toReturn = new List<T>();
            }
        }
        if (toReturn.Any())
        {
            yield return toReturn;
        }
    }
}

然后保留子集

void Insert()
{
    var actual = Get();
    using (var db = new DataClassesDataContext())
    {
        foreach (var set in actual.InSetsOf(5))
        {
            db.Shapes.InsertAllOnSubmit(set);
            db.SubmitChanges();
        }
    }
}

您可能还会在InsertOnSubmit()和InsertAllOnSubmit()上找到this MSDN article有用。

答案 3 :(得分:1)

要获得从IEnumerable获取批量项目的简洁方法,请参阅:

C#: Cleanest way to divide a string array into N instances N items long

更新:不好,适用于阵列。如果我有一段时间以后没有其他人提供过什么,我会把它写出来......