我正在寻找插入实体框架的最快方法。

我之所以问这个问题,是因为您有一个活动的TransactionScope,并且插入量很大(4000+)。它可能会持续超过10分钟(事务的默认超时),这将导致事务不完整。


当前回答

最快的方法是使用批量插入扩展,这是我开发的

注:这是一种商业产品,不是免费的

它使用SqlBulkCopy和自定义数据读取器来获得最大性能。因此,它比使用常规插入或AddRange快20倍以上

用法非常简单

context.BulkInsert(hugeAmountOfEntities);

其他回答

您应该考虑为此使用System.Data.SqlClient.SqlBulkCopy。这是文档,当然还有很多在线教程。

抱歉,我知道您正在寻找一个简单的答案来让EF做您想做的事情,但批量操作并不是ORM真正的用途。

是的,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();
                }
            }
        }
    }
}

这种组合可以很好地提高速度。

context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;

Configuration.LazyLoadingEnabled=false;Configuration.ProxyCreationEnabled=false;

如果没有AutoDetectChangesEnabled=false,这些速度太快;我建议使用不同于dbo的表头。通常我使用nop、sop、tbl等。。

另一种选择是使用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();
}

有关更多示例和高级用法,请参阅文档。免责声明:我是这个图书馆的作者,任何观点都是我自己的观点。