【问题标题】:How to do fast bulk insert through EF on related SQL tables?如何通过 EF 对相关 SQL 表进行快速批量插入?
【发布时间】:2017-11-06 03:53:25
【问题描述】:

我有一个包含 2 个表的数据库:

Apartment: ID, Name, Address
Tenant: ID, Name, Phone, ApartmentID

每个公寓可以有多个租户,但每个租户只能住在一个公寓中。

还有一个 API 可以返回当前的公寓列表,以及该公寓中的租户列表作为 JSON 列表:

Apartments : [
    { 
        Name: 'Sherwood', 
        Address: '21 Woody Lane' ,  
        Tenants : [
            { Name: 'Robin', Phone: '111-1111' },
            { Name: 'Hood', Phone: '222-2222' } 
        ]
    }, 

    ...


]

我需要将 API 结果解析为 2 个相关对象,公寓和租户,并将它们插入数据库。 API 返回的条目很多,大约 500,000 条。为了加快速度,我从以下方面获取了一些想法:Fastest Way of Inserting in Entity Framework

但是,该帖子中有一个概念我无法在我的解决方案中实现,即推迟 SaveChanges()。这就是我目前拥有代码(概念)的方式:

Foreach apartment
    Insert apartment into DB
    SaveChanges()
    Get ID of inserted apartment
    Foreach tenant in apartment
         Insert tenant into DB, into apartment ID

上述结构的原因是,在插入租户行时,我需要该租户居住的公寓 ID,因此我需要在之前插入(并保存更改以获取 ID)公寓插入租户。

这会导致 SaveChanges() 被多次调用并损害性能。上述方案如何优化?

【问题讨论】:

    标签: sql-server performance entity-framework bulkinsert


    【解决方案1】:

    您可以分配给导航属性 - EF 将在保存时处理它,如下所示:

    Foreach apartment
      dbContext.Appartments.Add(apartment);
      foreach tenant
        tenant.Appartment = apartment;
        dbContext.Tenants.Add(tenant);
      endforeach tenant
    endforeach apartment
    
    SaveChanges();
    

    【讨论】:

      【解决方案2】:

      实体框架中没有Bulk Insert。您必须使用第三方库来执行此类操作。

      默认情况下,Entity Framework 将为每个要保存的实体进行数据库往返。因此,在您的场景中需要超过 500,000 次数据库往返,这INSANELY很慢。


      免责声明:我是Entity Framework Extensions的所有者

      此库不是免费的,但允许您执行所有批量操作,包括 BulkInsert 并自动返回 Id's。您还可以使用IncludeGraph 选项插入相关实体:

      • 批量保存更改
      • 批量插入
      • 批量删除
      • 批量更新
      • 批量合并

      例子

      // Easy to use
      context.BulkSaveChanges();
      
      // Easy to customize
      context.BulkSaveChanges(bulk => bulk.BatchSize = 100);
      
      // Perform Bulk Operations
      context.BulkDelete(customers);
      context.BulkInsert(customers);
      context.BulkUpdate(customers);
      
      // Customize Bulk Operations
      context.BulkInsert(customers, options => {
         options => options.IncludeGraph = true;
      });
      context.BulkMerge(customers, options => {
         options.ColumnPrimaryKeyExpression = 
              customer => customer.Code;
      });
      

      【讨论】:

        猜你喜欢
        • 2020-05-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多