我正在寻找插入实体框架的最快方法。
我之所以问这个问题,是因为您有一个活动的TransactionScope,并且插入量很大(4000+)。它可能会持续超过10分钟(事务的默认超时),这将导致事务不完整。
我正在寻找插入实体框架的最快方法。
我之所以问这个问题,是因为您有一个活动的TransactionScope,并且插入量很大(4000+)。它可能会持续超过10分钟(事务的默认超时),这将导致事务不完整。
当前回答
另一种选择是使用Nuget提供的SqlBulkTools。它非常容易使用,并且具有一些强大的功能。
例子:
var bulk = new BulkOperations();
var books = GetBooks();
using (TransactionScope trans = new TransactionScope())
{
using (SqlConnection conn = new SqlConnection(ConfigurationManager
.ConnectionStrings["SqlBulkToolsTest"].ConnectionString))
{
bulk.Setup<Book>()
.ForCollection(books)
.WithTable("Books")
.AddAllColumns()
.BulkInsert()
.Commit(conn);
}
trans.Complete();
}
有关更多示例和高级用法,请参阅文档。免责声明:我是这个图书馆的作者,任何观点都是我自己的观点。
其他回答
我正在寻找插入实体框架的最快方法
有一些支持大容量插入的第三方库可用:
Z.EntityFramework.Extensions(推荐)EF实用程序实体框架.BulkInsert
请参见:实体框架大容量插入库
选择大容量插入库时要小心。只有实体框架扩展支持所有类型的关联和继承,并且它是唯一一个仍然受支持的实体框架扩展。
免责声明:我是实体框架扩展的所有者
此库允许您执行场景所需的所有批量操作:
批量保存更改大容量插入批量删除批量更新批量合并
实例
// 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 Primary Key
context.BulkMerge(customers, operation => {
operation.ColumnPrimaryKeyExpression =
customer => customer.Code;
});
最快的方法是使用批量插入扩展,这是我开发的
注:这是一种商业产品,不是免费的
它使用SqlBulkCopy和自定义数据读取器来获得最大性能。因此,它比使用常规插入或AddRange快20倍以上
用法非常简单
context.BulkInsert(hugeAmountOfEntities);
是的,SqlBulkUpdate确实是这类任务最快的工具。我想在.NETCore中找到“最省力”的通用方法,所以我最终使用了MarcGravell的优秀库FastMember,并为实体框架DB上下文编写了一个小小的扩展方法。工作速度极快:
using System.Collections.Generic;
using System.Linq;
using FastMember;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
namespace Services.Extensions
{
public static class DbContextExtensions
{
public static void BulkCopyToServer<T>(this DbContext db, IEnumerable<T> collection)
{
var messageEntityType = db.Model.FindEntityType(typeof(T));
var tableName = messageEntityType.GetSchema() + "." + messageEntityType.GetTableName();
var tableColumnMappings = messageEntityType.GetProperties()
.ToDictionary(p => p.PropertyInfo.Name, p => p.GetColumnName());
using (var connection = new SqlConnection(db.Database.GetDbConnection().ConnectionString))
using (var bulkCopy = new SqlBulkCopy(connection))
{
foreach (var (field, column) in tableColumnMappings)
{
bulkCopy.ColumnMappings.Add(field, column);
}
using (var reader = ObjectReader.Create(collection, tableColumnMappings.Keys.ToArray()))
{
bulkCopy.DestinationTableName = tableName;
connection.Open();
bulkCopy.WriteToServer(reader);
connection.Close();
}
}
}
}
}
正如其他人所说,如果您想要真正好的插入性能,SqlBulkCopy是一种实现方法。
它的实现有点麻烦,但有一些库可以帮助您实现它。有一些库,但这次我将无耻地使用我自己的库:https://github.com/MikaelEliasson/EntityFramework.Utilities#batch-插入实体
您需要的唯一代码是:
using (var db = new YourDbContext())
{
EFBatchOperation.For(db, db.BlogPosts).InsertAll(list);
}
那么它快多少?很难说,因为这取决于许多因素,计算机性能、网络、对象大小等。我所做的性能测试表明,如果您像其他答案中提到的那样优化EF配置,则可以在10秒左右以标准方式在本地主机上插入25k个实体。使用EFUtilities,大约需要300毫秒。更有趣的是,我使用这种方法在不到15秒内保存了大约300万个实体,平均每秒大约200万个实体。
当然,一个问题是若需要插入相关数据。这可以使用上述方法在sql server中高效地完成,但它需要您有一个Id生成策略,允许您在应用程序代码中为父级生成Id,以便您可以设置外键。这可以使用GUID或类似HiLo id生成的方法来完成。
另一种选择是使用Nuget提供的SqlBulkTools。它非常容易使用,并且具有一些强大的功能。
例子:
var bulk = new BulkOperations();
var books = GetBooks();
using (TransactionScope trans = new TransactionScope())
{
using (SqlConnection conn = new SqlConnection(ConfigurationManager
.ConnectionStrings["SqlBulkToolsTest"].ConnectionString))
{
bulk.Setup<Book>()
.ForCollection(books)
.WithTable("Books")
.AddAllColumns()
.BulkInsert()
.Commit(conn);
}
trans.Complete();
}
有关更多示例和高级用法,请参阅文档。免责声明:我是这个图书馆的作者,任何观点都是我自己的观点。