我正在使用EF 6.我试图插入大约200.000个实体,同时在每100个实体之后保存对数据库的更改。
问题是需要11个小时来保存50.000个实体,它仍然落后。我正在使用WebJobs运行它,并且作业在与主网站相同的azure webapp上发布。是因为这个问题和WebJob没有足够的资源,或者在100个实体之后保存,还是方法?
方式
public void SaveLeadsForBuyer(ISenderModel model)
{
var rowCounter = 0;
foreach (var deliveryRecord in model.Customers.Select(customerModel => new DeliveryRecord()
{
BuyerId = model.Buyer.Id,
AspNetUserId = customerModel.Id,
DeliveryType = model.Buyer.DeliveryType,
CreatedOn = DateTime.UtcNow
}))
{
++rowCounter;
_unit.Repository<DeliveryRecord>().Insert(deliveryRecord);
_unit.SaveChangesPartially(rowCounter, 100);
}
_unit.SaveChanges();
}
辅助
public static class UnitOfWorkHelper
{
/// <summary>
/// Helper method triggers SaveChanges() after amount of rows provided through "amount" parameter in method
/// </summary>
/// <param name="unit">UnitOfWork object</param>
/// <param name="count">Current amount of rows</param>
/// <param name="saveCount">Amount when to save changes to database</param>
public static void SaveChangesPartially(this IUnitOfWorkAsync unit, int count, int saveCount)
{
if (count % saveCount == 0)
{
unit.SaveChanges();
}
}
}
答案 0 :(得分:5)
这很慢,因为Entity Framework为每条记录执行数据库往返。因此,如果您节省了200,000个实体,那么将执行 200,000次数据库往返,这对于保存多个实体来说是最佳的。
对于这种情况,您需要自己实现或使用支持BulkInsert的库(通常在引擎盖下执行SqlBulkCopy)
有3个主库(2个免费,1个PRO)允许批量插入
// Example from Entity Framework Extensions Library
using (var ctx = new EntitiesContext())
{
ctx.BulkInsert(list);
}
您可以阅读以下文章,了解PROS&amp;每个图书馆的缺点:Entity Framework - Bulk Insert Library Reviews & Comparisons
Entity Framework Extensions是提供最大灵活性的库(批量插入,更新,删除,合并和BulkSaveChanges并支持所有内容),但它是PRO版本。如果您正在寻找免费版本,我建议使用EntityFramework.BulkInsert,但是,它不再受支持,并且不支持所有关联和继承。
免责声明:我是该项目的所有者Entity Framework Extensions
编辑:回答评论问题
我保存每100条记录,而不是每条记录
如果向单元上下文添加一个实体或100个实体并不重要,实体框架会逐个保存它们(每个记录都有一个插入语句)。只需将SQL事件探查器与SQL Server数据库一起使用,您就会明白我的意思。
编辑:回答评论问题
伟大的乔纳森。有没有办法用ef6 generic实现这个 UOW?
答案取决于您选择使用哪个库。
如果你使用我的库,你可以创建BulkSaveChanges方法或在你的UnitOfWork中更改所有“_context.SaveChanges()”“_context.BulkSaveChanges()”
public void SaveLeadsForBuyer(ISenderModel model)
{
// ... code ...
// _unit.SaveChanges();
_unit.BulkSaveChanges();
}
如果你想从我的库或免费库中获得最佳性能和实现批量插入,我可能会添加名为BulkInsert的方法或扩展方法(如果你不能更改存储库类)
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
// ... code ...
public virtual void BulkInsert(List<TEntity> list)
{
_context.BulkInsert(list);
}
}
请记住BulkInsert直接插入实体而不必调用“SaveChanges”,它不会使用上下文/更改跟踪器来获得最佳性能。