【问题标题】:bulk insert with linq-to-sql使用 linq-to-sql 进行批量插入
【发布时间】:2012-02-10 00:08:00
【问题描述】:

我的查询如下所示:

using (MyDC TheDC = new MyDC())
{
   foreach (MyObject TheObject in TheListOfMyObjects)
   {
      DBTable TheTable = new DBTable();

      TheTable.Prop1 = TheObject.Prop1;
      .....
      TheDC.DBTables.InsertOnSubmit(TheTable);

   }
   TheDC.SubmitChanges();
}

这个查询基本上是使用 linq-to-sql 将一个列表插入到数据库中。现在我在网上看到 L2S 不支持批量操作。 我的查询是一次插入每个元素还是一次插入所有元素?

感谢您的澄清。

【问题讨论】:

    标签: c# linq linq-to-sql


    【解决方案1】:

    我修改了以下链接中的代码以提高效率并在我的应用程序中使用它。这非常方便,因为您可以将它放在当前自动生成的类之上的部分类中。代替InsertOnSubmit 将实体添加到列表中,而不是SubmitChanges 调用YourDataContext.BulkInsertAll(list)

    http://www.codeproject.com/Tips/297582/Using-bulk-insert-with-your-linq-to-sql-datacontex

    partial void OnCreated()
    {
        CommandTimeout = 5 * 60;
    }
    
    public void BulkInsertAll<T>(IEnumerable<T> entities)
    {                        
        using( var conn = new SqlConnection(Connection.ConnectionString))
        {
            conn.Open();
    
            Type t = typeof(T);
    
            var tableAttribute = (TableAttribute)t.GetCustomAttributes(
                typeof(TableAttribute), false).Single();
            var bulkCopy = new SqlBulkCopy(conn)
            {
                DestinationTableName = tableAttribute.Name
            };
    
            var properties = t.GetProperties().Where(EventTypeFilter).ToArray();
            var table = new DataTable();
    
            foreach (var property in properties)
            {
                Type propertyType = property.PropertyType;
                if (propertyType.IsGenericType &&
                    propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    propertyType = Nullable.GetUnderlyingType(propertyType);
                }
    
                table.Columns.Add(new DataColumn(property.Name, propertyType));
            }
    
            foreach (var entity in entities)
            {
                table.Rows.Add(
                    properties.Select(
                    property => property.GetValue(entity, null) ?? DBNull.Value
                    ).ToArray());
            }
    
            bulkCopy.WriteToServer(table);
        }                                               
    }
    
    private bool EventTypeFilter(System.Reflection.PropertyInfo p)
    {
        var attribute = Attribute.GetCustomAttribute(p,
            typeof(AssociationAttribute)) as AssociationAttribute;
    
        if (attribute == null) return true;
        if (attribute.IsForeignKey == false) return true;
    
        return false;
    }
    

    【讨论】:

    • 使用 Linqpad 我必须 t.GetProperties().Where(EventTypeFilter)t.GetFields()。一分钟内插入了 200k 行! (y)
    • 对此赞不绝口。我的 212 条记录的测试插入需要 50 秒,这将其缩短到 1.3 秒。当我实际插入 10k 条记录时应该会有所帮助!
    • 看看这个:stackoverflow.com/a/21382542/1246870 - 对我来说效果很好
    • 如何在不需要新数据上下文的情况下获取和设置批量插入记录的 ID 属性?
    • 我将 EF 留在 SaveChanges() 上过夜,发现我的 VM 在早上死了。这在 8 秒内插入了 100 万行,谢谢!
    【解决方案2】:

    Bulk Insert 一词通常指的是 SQL Server 特定的基于超快速 bcp 的 SqlBulkCopy 实现。它建立在IRowsetFastLoad 之上。

    Linq-2-SQL 在any 条件下不使用这种机制实现插入。

    如果您需要将数据批量加载到 SQL Server 并需要它的速度,我建议使用 SqlBulkCopy 进行手动编码。

    Linq-2-SQL 将尝试执行一些优化以加速多次插入,但它仍然无法满足许多微 ORM(即使我知道没有实现 SqlBulkCopy 的微 ORM)

    【讨论】:

      【解决方案3】:

      它将为每条记录生成一个插入语句,但会将它们全部发送到单个批处理中的服务器并在单个事务中运行。

      这就是循环外的 SubmitChanges() 所做的。

      如果你把它移到里面,那么循环中的每次迭代都会去服务器进行 INSERT 并在它自己的事务中运行。

      我不相信有任何方法可以触发 SQL BULK INSERT。

      【讨论】:

      【解决方案4】:

      LINQ 从列表中单次插入:

                      int i = 0;
                      foreach (IPAPM_SRVC_NTTN_NODE_MAP item in ipapmList)
                      {
                          ++i;
                          if (i % 50 == 0)
                          {
                              ipdb.Dispose();
                              ipdb = null;
                              ipdb = new IPDB();
                              // .NET CORE
                              //ipdb.ChangeTracker.AutoDetectChangesEnabled = false; 
                              ipdb.Configuration.AutoDetectChangesEnabled = false;
                          }
      
                          ipdb.IPAPM_SRVC_NTTN_NODE_MAP.Add(item);
                          ipdb.SaveChanges();
                      }                 
      

      【讨论】:

        【解决方案5】:

        我建议你看看 N.EntityFramework.Extension。它是 EF 6 的基本批量扩展框架,可在 Nuget 上获得,源代码可在 MIT 许可下在 Github 上获得。

        Install-Package N.EntityFramework.Extensions
        

        https://www.nuget.org/packages/N.EntityFramework.Extensions

        安装后,您可以直接在 DbContext 实例上使用 BulkInsert() 方法。它支持 BulkDelete、BulkInsert、BulkMerge 等。

        BulkInsert()

        var dbcontext = new MyDbContext();  
        var orders = new List<Order>();  
        for(int i=0; i<10000; i++)  
        {  
           orders.Add(new Order { OrderDate = DateTime.UtcNow, TotalPrice = 2.99 });  
        }  
        dbcontext.BulkInsert(orders);  
        

        【讨论】:

          猜你喜欢
          • 2010-12-09
          • 2011-04-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多