回答
只需从您的对象列表中选择create a DataTable,然后调用SqlBulkCopy.WriteToServer
,传递数据表。
您可能会发现下面的有用:
- Adding columns to a DataTable。为您希望编写的每个属性/字段添加一列。
- Adding rows to a DataTable。为列表中的每个对象添加一行。
为了获得SqlBulkCopy的最佳性能,您应该设置合适的BatchSize。 10,000似乎运作良好 - 但对您的数据进行了描述。
使用SqlBulkCopyOptions.TableLock时,您可能会观察到更好的结果。
SqlBulkCopy性能的一个有趣的和翔实的分析可以找到here。
随着FastMember,你可以这样做而没有通过需要DataTable
(在我的测试中,更比加倍性能)去:
using(var bcp = new SqlBulkCopy(connection))
using(var reader = ObjectReader.Create(data, "Id", "Name", "Description"))
{
bcp.DestinationTableName = "SomeTable";
bcp.WriteToServer(reader);
}
注意ObjectReader
也可以与非工作并且没有必要预先指定成员名称(尽管如果您没有在ObjectReader
本身中指定它们,您可能希望使用SqlBulkCopy
的ColumnMappings
方面)。
根据您试图通过首先调用SqlBulkCopy
来完成的工作,使用Table-Valued Parameter(TVP)可能更有意义。使用TVP将使发送任何自定义类型的集合变得微不足道。数据可以流入,因此您可以避免DataTable
(很像在@Marc Gravell的答案中),您也可以避免SqlBulkCopy
。当你调用一个存储过程传递TVP数据时,TVP允许完全灵活地处理数据,一旦它到达SQL Server,它就表现为表变量,你可以做任何事情,而不仅仅是INSERT
(这是情况与SqlBulkCopy
)。您也可以通过SqlDataReader
获取数据,例如新创建的IDENTITY
值。我在这个答案中增加了一个例子和一些附加注释:How can I insert 10 million records in the shortest time possible?。几年前,我写了一篇关于SQL Server Central的文章(需要免费注册),Streaming Data Into SQL Server 2008 From an Application,这也在该链接的答案中提到,提供了一个传递自定义类型的通用列表的工作示例,从300万行文本文件。
迟到了,但如果添加此Microsoft EntityDataReader
类,有一个AsDataReader()
扩展方法正是这么做的:https://github.com/matthewschrager/Repository/blob/master/Repository.EntityFramework/EntityDataReader.cs
(例如[List].AsDataReader()
实现:)
var connStr = "";
using (var connection = new SqlConnection(connStr))
{
var startTime = DateTime.Now;
connection.Open();
var transaction = connection.BeginTransaction();
try
{
//var connStr = connection.ConnectionString;
using (var sbCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
{
sbCopy.BulkCopyTimeout = 0;
sbCopy.BatchSize = 10000;
sbCopy.DestinationTableName = "Foobars";
var reader = Foobars.AsDataReader();
sbCopy.WriteToServer(reader);
}
transaction.Commit();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
transaction.Rollback();
}
finally
{
transaction.Dispose();
connection.Close();
var endTime = DateTime.Now;
Console.WriteLine("Upload time elapsed: {0} seconds", (endTime - startTime).TotalSeconds);
}
}
- 1. 从列表中返回一个列表<SomeType><AnotherType>
- 2. 从列表返回一个匹配<KeyValuePair <string,string >>
- 3. 从列表<>
- 4. 序列化列表<一个LinkedListNode <object>>使用Json.net
- 5. 两个BackgroundWorkers,一个列表<T>
- 6. 将5个列表<object>合并成一个列表<object>
- 7. 从另一个过滤一个列表<string>通过LINQ
- 8. 列表<Object>和列表<?>
- 9. 更新一个列表<T>从另一个列表中<T>当数据变化
- 10. 从XML构建列表<列表<XElement>>
- 11. 从列表<myType>继承或扩展列表<myType>
- 12. 提取列表<>从列表<>
- 13. 无法从列表<Bar>转换到列表<Foo>
- 14. 从列表<class>
- 15. C#JSON从列表<>
- 16. 从列表<>在C#
- 17. 转换列表<T>到列表<string>一般
- 18. Collections.emptyList()返回一个列表<Object>?
- 19. 从LINQ查询创建一个字典<INT,列表<int>>
- 20. 更新列表<select>从另一个<select multiple>使用jquery
- 21. 类的设计 - 返回一个列表<Object>从<Object>
- 22. 检查列表<string>是否包含在另一个列表<string>
- 23. C#重新排序列表<string>基于另一个列表<string>
- 24. 转换列表<T>到包含另一个列表<T>
- 25. 从列表中创建一个单一的项目列表<string><object>
- 26. 从匹配两个分开的列表中获取一个列表<T><T> s
- 27. 列表<Product>。加入(列表<Order>,...)与列表<Order>。加入(列表<Product>,...)?
- 28. 列表<>与多个列表C#
- 29. 无法从列表<map <string,object >>转换为列表<map <string,string >>
- 30. 加入多个列表<string[]>到一个新列表
迟到了,但是如果你添加这个'EntityDataReader'类,那么就有一个'AsDataReader()'扩展方法,它的确如此:https:// github。com/matthewschrager/Repository/blob/master/Repository.EntityFramework/EntityDataReader.cs – RJB 2016-04-23 21:52:38
(请参阅下面的全新实施答案) – RJB 2016-04-23 22:31:13