使用linq-to-sql进行批量插入

时间:2012-02-10 00:08:01

标签: c# linq linq-to-sql

我有一个如下所示的查询:

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不支持批量操作。 我的查询是通过一次插入每个元素还是一次写入来完成的?

感谢您的澄清。

5 个答案:

答案 0 :(得分:27)

我修改了以下链接中的代码以提高效率并在我的应用程序中使用它。它非常方便,因为您可以将它放在当前自动生成的类之上的部分类中。而不是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;
}

答案 1 :(得分:8)

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

Linq-2-SQL在任何条件下不使用此机制实现插入。

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

Linq-2-SQL将尝试执行一些优化来加速多个插入,但是它仍然会达不到许多微ORM(即使没有我知道实现SqlBulkCopy的微ORM)

答案 2 :(得分:4)

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

这就是循环外的SubmitChanges()。

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

我不相信有任何方法可以启动SQL BULK INSERT。

答案 3 :(得分:0)

列表中的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();
                }                 

答案 4 :(得分:0)

我建议您看看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);