我目前的项目由 3 个标准层组成:数据、业务和表示。我想使用数据实体来满足我所有的数据访问需求。该应用程序的部分功能是需要将平面文件中的所有数据复制到数据库中。该文件不是那么大,所以我可以使用 SqlBulkCopy。我找到了几篇关于 .NET 中使用 SqlBulkCopy 类的文章。但是,所有文章都使用 DataTables 来回移动数据。
有没有办法将数据实体与 SqlBulkCopy 一起使用,还是我必须使用 DataTables?
我目前的项目由 3 个标准层组成:数据、业务和表示。我想使用数据实体来满足我所有的数据访问需求。该应用程序的部分功能是需要将平面文件中的所有数据复制到数据库中。该文件不是那么大,所以我可以使用 SqlBulkCopy。我找到了几篇关于 .NET 中使用 SqlBulkCopy 类的文章。但是,所有文章都使用 DataTables 来回移动数据。
有没有办法将数据实体与 SqlBulkCopy 一起使用,还是我必须使用 DataTables?
您需要将实体转换为 IDataReader 或 DataTable。
有一个小助手类旨在协助: http: //archive.msdn.microsoft.com/LinqEntityDataReader/Release/ProjectReleases.aspx?ReleaseId =389
编辑:msdn 链接已损坏,可在此处找到替代副本: https ://github.com/matthewschrager/Repository/blob/master/Repository.EntityFramework/EntityDataReader.cs
然后你可以像这样使用 SqlBulkCopy:
var sbCopy= new SqlBulkCopy(connectionString);
sbCopy.DestinationTableName = "TableName";
sbCopy.WriteToServer(entitiesList.AsDataReader());
在使用 EF 进行批量插入时,我们尝试并测试了几种方法,最终使用表值参数在一系列行大小下获得最佳性能。我手头没有数字,但我知道bcp/BULK INSERT 与表值参数的性能是一个指导因素。
我们最初使用SqlBulkCopy
与一个适配器耦合,该适配器采用IEnumerable<T>
并创建一个IDataReader
. 它还为 SqlBulkCopy 生成了相关的元数据。这里的优点是导入只是代码。@davehogan 发布的代码被用作此的基础。
表值参数需要在数据库中定义的存储过程和表类型。如果您使用代码优先,您可以执行 SQL 来创建这些作为创建脚本的一部分。虽然这是更多的工作,但我们发现我们在数据库中获得了更加一致和更快的行吞吐量。
此外,值得考虑不要批量插入主表。我们使用临时堆表并在导入数据后为其添加聚集索引。MERGE
然后我们在临时表和主表之间执行一个。这样做的好处是在插入时不锁定主表的索引并提高了并发性。使用这种方法插入的每个 CPU,我们倾向于获得超过 2500 行/秒的数据。
如果您想了解更多信息,请告诉我。
SqlBulkCopy 在调用 WriteToServer 方法时使用 IDataReader,因此您应该能够基于 IEnumerable 的集合实现 IDataReader。这将允许您接收一个实体集并使用您的 IDataReader 实现调用 SqlBulkCopy。
您可以将 Dataset 视为数据实体的序列化。但是一般来说,我认为 SqlBulkCopy 是一个表到表的东西,因此是数据表的原因。
SqlBulkCopy 是一种直接的、几乎类似于字节数组的行数据从客户端到 SQL Server 的传输。这是将数据导入 SQL Server 的最有效方式。
然而,它的性能在于真正的“批量”操作。数百或数千行不一定高到足以证明使用的合理性。数万到数百万行都是 SqlBulkCopy 的性能才会真正大放异彩。最后,我们真正谈论的只是将数据发送到服务器。
将一组行放入生产数据库的表中还有其他重大挑战。重新索引、重新排序(如果有聚集索引)、外键验证,所有这些类型的事情都会增加插入时间,并且可能会锁定表和索引。
此外,TVP 数据被写入磁盘(作为临时表数据),然后可以访问以放入您的表中。SqlBulkCopy 能够直接进入您的餐桌......在这种情况下性能明显更快,但是,必须平衡并发速度。
我认为总体规则是,如果您有少量行要处理,请考虑 TVP,如果您有数千行,请考虑通过 SqlBulkCopy 尽快将其发送到 SQL Server。