EF4 SaveChanges, как избежать исключения нехватки памяти

Существующий фрагмент

foreach (var ownerCandidates in ownerToCandidatesDictionary)
  {
    foreach (var candidate in ownerCandidates.Value)
    {
       transactionEntities.AddToSomeEntity(someObject)
    }
  }
                transactionEntities.SaveChanges(System.Data.Objects.SaveOptions.AcceptAllChangesAfterSave);

Переписывает на

    int i = 0 ; 
    foreach (var ownerCandidates in ownerToCandidatesDictionary)
    {
         foreach (var candidate in ownerCandidates.Value)
         {
             transactionEntities.AddToSomeEntity(someObject)
          }
          if ( i++ % 1000 == 0 ) 
          {
               transactionEntities.SaveChanges(System.Data.Objects.SaveOptions.AcceptAllChangesAfterSave);
          } 
    }

transactionEntities.SaveChanges(System.Data.Objects.SaveOptions.AcceptAllChangesAfterSave);

дает нам ту же функциональность в случае успешного завершения программы? Меня беспокоит, что мы продолжаем добавлять, работает ли SaveChanges в цикле только с тем, что было добавлено с момента предыдущего SaveChanges. У нас есть сохранение партиями? Если это не так, как можно изменить исходный фрагмент, чтобы избежать

12/06/2012 7:50:37 PM : System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
   at System.Data.Mapping.Update.Internal.Propagator.Project(DbProjectExpression node, PropagatorResult row, TypeUsage resultType)
   at System.Data.Mapping.Update.Internal.Propagator.Visit(DbProjectExpression node)
   at System.Data.Common.CommandTrees.DbProjectExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
   at System.Data.Mapping.Update.Internal.Propagator.Propagate(UpdateTranslator parent, EntitySet table, DbQueryCommandTree umView)
   at System.Data.Mapping.Update.Internal.UpdateTranslator.<ProduceDynamicCommands>d__0.MoveNext()
   at System.Linq.Enumerable.<ConcatIterator>d__71`1.MoveNext()
   at System.Data.Mapping.Update.Internal.UpdateCommandOrderer..ctor(IEnumerable`1 commands, UpdateTranslator translator)
   at System.Data.Mapping.Update.Internal.UpdateTranslator.ProduceCommands()
   at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
   at System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache)
   at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)

person MicMit    schedule 13.06.2012    source источник


Ответы (1)


Последующий вызов SaveChanges() не будет иметь никакого эффекта, если не будут внесены изменения в набор объектов после предыдущего вызова SaveChanges(). После SaveChanges() в базу данных поступает новая партия. Пакетная обработка — это возможность преодолеть OutOfMemoryException во время огромных вставок с помощью EntityFramework. На самом деле SaveChanges() следует вызывать только один раз, но в вашем случае, поскольку данные огромны, их необходимо разделить на пакеты.

Кроме того, при массовом добавлении объекта для значительного повышения производительности временно отключите автоматическое обнаружение изменений, установив для параметра AutoDetectChangesEnabled значение false. Вот информацияcontext.Configuration.AutoDetectChangesEnabled = false;

person Abhijit-K    schedule 13.06.2012
comment
Но как насчет фрагментов кода, которые я включил, фрагмент 2 — вы видите там пакеты. - person MicMit; 13.06.2012
comment
Да, линия if ( i++ % 1000 == 0 ) делает партии. При каждой партии 1000 вкладышей. - person Abhijit-K; 13.06.2012