实体框架慢AddRange插入到DB

时间:2015-03-15 09:24:15

标签: c# entity-framework

我正在实现Database First Entity Framework 6.1,以向SQL Server db插入大约2000个主/详细信息集合。每个集合大约有2~3个对象。所以要插入的总数或记录是〜5000。事务大约需要2~3min,这是非常慢的。我使用的是以下代码:

public class Collection
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }

    ...

    public List<DetailCol> Details{ get; set; } 
}


public class DetailCol
    {
        [Key]
        public int Id { get; set; }
        public decimal Lvl { get; set; }
        public string Type { get; set; }
    }

var MyCollections = new List<Collection>();

// Do population of collection and try to insert to db

using (var db = new MyContext(ConnectionString)
{
    // Speed up insert
    db.Configuration.AutoDetectChangesEnabled = false;

    // Add new entries to master and details
    db.MyCollections.AddRange(MyCollections);

    // Update db
    db.SaveChanges();
}

有人可以暗示为什么会发生这种情况以及如何改善这种情况吗?

2 个答案:

答案 0 :(得分:1)

我刚刚经历过同样的事情,并且AddRange()在EF 6.1中只需要几分钟就可以添加1200条记录,因为当你查看探查器时它一次只进行一次INSERTS,所以BulkCopy将是你最快的选择。好消息是基本的表插入,您可以通过安装此nuget包使用名为EntityFramework.BulkInsert的扩展:EFBulkInsert

添加:使用EntityFramework.BulkInsert.Extensions; 然后做这样的事情:

var options = new BulkInsertOptions();
options.BatchSize = 1000; // Default is 5000
efContext.BulkInsert<MyObject>(myList, options);
efContext.SaveChanges();

我从几分钟到2-3秒,甚至从我的计算机到Azure SQL数据库。

答案 1 :(得分:0)

我的解决方案使用nuget Extensions.EntityFrameworkCore.SqlServer.Bulk中的批量插入来更新表数据

public async Task Execute(IList<TDest> outRows ,CancellationToken stoppingToken)
        {
            var mapping = _destCtx.Model.FindEntityType(typeof(TDest)).Relational();
            var strategy = _destCtx.Database.CreateExecutionStrategy();
            await strategy.ExecuteAsync(async () =>
            {
                using (var tran = _destCtx.Database.BeginTransaction())
                {
                    try
                    {
                        //var dest = _destCtx.Set<TDest>();
                        //dest.RemoveRange(dest);
                        await _destCtx.Database.ExecuteSqlCommandAsync((string)$"TRUNCATE TABLE {mapping.Schema}.{mapping.TableName}");
                        //await _destCtx.BulkDeleteAsync(dest, null, stoppingToken);
                        //dest.AddRange(outRows);
                        await _destCtx.BulkInsertAsync(outRows, null, stoppingToken);

                        //await _destCtx.SaveChangesAsync(stoppingToken);

                        tran.Commit();
                    }
                    catch (Exception)
                    {
                        tran.Rollback();
                        throw;
                    }
                }
            });
        }
    }