代码之家  ›  专栏  ›  技术社区  ›  griegs

实体框架4在保存更改时内存不足

  •  3
  • griegs  · 技术社区  · 11 年前

    我有一张包含50多万条记录的表。每条记录包含大约60个字段,但我们只对其中三个字段进行了更改。

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

    很明显,我无法依次更新每个实体 SaveChanges 因为那样会花费太长时间。

    所以在整个过程结束时,我打电话给 保存更改 Context .

    当我应用时,这会导致内存不足错误 保存更改

    我使用的是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();
    }
    

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

    1 回复  |  直到 11 年前
        1
  •  4
  •   Ladislav Mrnka    11 年前

    在一笔交易中通过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();
           }
        }
    }
    

    此代码使用单独的上下文来保存项目=每个保存都在自己的事务中。不要害怕。即使您试图在一次呼叫内保存更多记录 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 (在枚举过程中修改集合)-但我不确定这是否真的发生了。

    修改这些示例以使用某些批次应该很容易。