Как предотвратить переполнение памяти при использовании IEnumerable <T>и Linq-To-Sql? - PullRequest
1 голос
/ 23 июня 2009

Этот вопрос относится к моему предыдущему вопросу

Это мой текущий код

 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 ]

3 голосов
/ 23 июня 2009

Попробуйте использовать InsertOnSubmit вместо InsertAllOnSubmit . А затем фиксируйте через определенные промежутки времени, как сказал Эрих.

Или, если вы хотите сделать это, например, партиями. 5, попробуйте Handcraftsman's или dtb решения для получения IEnumerable's IEnumerable. Например, с Dtb's Chunk:

   var actual = Get();
   using (var db = new DataClassesDataContext())
   {
       foreach(var batch in actual.Chunk(5))
       {
         db.Shapes.InsertAllOnSubmit(batch);
         db.SubmitChanges();
       }
   }
3 голосов
/ 23 июня 2009

Один из вариантов - разбить его на несколько партий. Создайте временный буфер из Shape объектов, итерируйте, пока вы его не заполните или не исчерпаете из перечислителя, затем выполните InsertBatchOnSubmit.

2 голосов
/ 24 июня 2009

Используйте следующий метод расширения, чтобы разбить входные данные на подмножества соответствующего размера

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

Также может оказаться полезной эта статья MSDN в InsertOnSubmit () против InsertAllOnSubmit ().

1 голос
/ 23 июня 2009

Для аккуратного способа получить партии предметов из IEnumerable, смотрите это:

C #: Самый простой способ разбить массив строк на N экземпляров длиной N элементов

Обновление: не хорошо, это работает на массивах. Если у меня будет какое-то время спустя и никто ничего не предоставит, я напишу это ...

...