实体框架4在SaveChanges上内存不足

本文关键字:内存不足 SaveChanges 框架 实体 | 更新日期: 2023-09-27 18:08:29

我有一个包含超过50万条记录的表。每条记录包含大约60个字段,但我们只更改其中的三个。

我们根据计算和查找对每个实体做一个小的修改。

显然,我不能依次更新每个实体,然后再更新SaveChanges,因为这将花费太长时间。

所以在整个过程的最后我调用SaveChangesContext

这是导致内存不足的错误,当我应用SaveChanges

我正在使用DataRepository模式。

//Update code
DataRepository<ExportOrderSKUData> repoExportOrders = new DataRepository<ExportOrderSKUData>();
foreach (ExportOrderSKUData grpDCItem in repoExportOrders.all())
{
  ..make changes to enity..
}
repoExportOrders.SaveChanges();

//Data repository snip
public DataRepository()
{
  _context = new tomEntities();
  _objectSet = _context.CreateObjectSet<T>();
}
public List<T> All()
{
  return _objectSet.ToList<T>();
}
public void SaveChanges()
{
  _context.SaveChanges();
}

在这种情况下我应该寻找什么?

实体框架4在SaveChanges上内存不足

在一个事务中通过EF更改50万条记录是不应该用例。小批量生产是一个更好的技术解决方案。在数据库端通过一些存储过程来完成它可能是更好的解决方案。

我将从稍微修改你的代码开始(自己把它翻译成你的存储库API):

using (var readContext = new YourContext()) {
    var set = readContext.CreateObjectSet<ExportOrderSKUData>();
    foreach (var item in set.ToList()) {
       readContext.Detach(item);
       using (var updateContext = new YourContext()) {
          updateContext.Attach(item);
          // make your changes
          updateContext.SaveChanges();
       }
    }
}

这段代码使用单独的上下文来保存item =每个保存都在自己的事务中。不要害怕。即使您尝试在一次SaveChanges调用中保存更多记录,EF也会为每个更新的记录使用单独的往返数据库。唯一的区别是如果你想在同一个事务中有多个更新(但是在一个事务中有50万个更新无论如何都会导致问题)。

另一个选项是:

using (var readContext = new YourContext()) {
    var set = readContext.CreateObjectSet<ExportOrderSKUData>();
    set.MergeOption = MergeOption.NoTracking;
    foreach (var item in set) {
       using (var updateContext = new YourContext()) {
          updateContext.Attach(item);
          // make your changes
          updateContext.SaveChanges();
       }
    }
}

这在理论上可以消耗更少的内存,因为您不需要在执行foreach之前加载所有实体。第一个例子可能需要在枚举之前加载所有实体(通过调用ToList),以避免在调用Detach(在枚举期间修改集合)时发生异常-但我不确定是否真的发生了。