2013-04-11 44 views
2

我有一个包含超过50万条记录的表。每个记录包含约60个字段,但我们只对其中三个进行更改。实体框架4 SaveChanges上的内存不足

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

很明显,我无法依次更新每个实体,然后SaveChanges,因为这将花费太长时间。

因此,在整个过程结束时,我拨打Context拨打SaveChanges

这当我申请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(); 
} 

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

+0

你说:“很明显,我无法轮流更新每个实体,然后SaveChanges会花费太长时间。”是否可以为'SaveChanges()'调用一些任意数量的记录(可能是1024或4096)? – 2013-04-11 05:57:41

+0

你看了下面的帖子,因此[http://stackoverflow.com/questions/5940225/fastest-way-of-inserting-in-entity-framework/5942176#5942176](http://stackoverflow.com//5942176#5942176)5940225 /插入式实体框架最快的方式 - 的 - 问题/? – 2013-04-11 05:59:29

+0

@David是的,我试过了,这似乎工作正常,但我不确定这是最好的*技术*解决方案。明白我的意思了吗? – griegs 2013-04-11 05:59:57

回答

3

在一次交易中通过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(在枚举期间修改集合)时发生异常 - 但我不确定这是否真的发生。

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

+0

即使他们不工作,我也喜欢这些。我仍然遇到内存不足错误。然而,我可以看到这个答案中的价值,我可能需要在这个项目中做的其他事情。谢谢 – griegs 2013-04-11 21:37:35

+1

您应该使用内存分析器来查找究竟是什么导致问题。如果这两个例子都不能解决OOM异常问题,那么可能会有一些更大的隐藏问题。 – 2013-04-11 22:44:19

+0

同意。这可能只是因为我的电脑内存不足,并且它不再是服务器上的问题,但现在我无法检查是否属于这种情况。有点奇怪在这里访问。 – griegs 2013-04-11 23:00:14