我有一张包含超过五十万条记录的表格。每条记录包含大约60个字段,但我们只对其中三个字段进行更改。
我们根据计算和查找对每个实体进行小修改。
显然,我无法依次更新每个实体,然后SaveChanges
,因为这需要太长时间。
所以在整个过程结束时,我在SaveChanges
上致电Context
。
当我应用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 :(得分: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
时出现异常(在枚举期间修改集合) - 但我不确定这是否真的发生了。 / p>
修改这些示例以使用某些批次应该很容易。