.NETentity framework插入与批量插入

当我使用我的xxxContext对象并向表发出几个Add时,然后SaveChanges()entity framework如何将其解析为SQL? 它只是循环插入xxx或者如果有数百行,它是否足够智能发出批量插入命令?

奖金问题:如果它没有发出批量插入有没有办法强制它,所以我的数据库性能不会被单独的插入杀死? 或者批量到临时表,然后像Upsert一样合并到原始表?

任何ORM工具的垮台都是“健谈”。 大部分时间这都足够好了。 有时它不是。

最简洁的答案是不”。

这就是为什么我有时仍会选择IDataReader而不是EF或NHibernate等。对于批量插入操作,我将xml发送到存储过程,然后我将其粉碎并从那里批量插入/更新或合并。

因此,即使我使用ORM,我创建的域库也不依赖于EF(或NHibernate)……所以我在某些情况下通过ORM有一个“安全阀”。

如果您的插入查询是ANSI SQL,或者您不关心使用您的代码库支持多重数据库,您仍然有后门从EF创建ADO.NET提供程序并执行一些原始SQL调用

https://stackoverflow.com/a/1579220/98491

我会做这样的事情

private void BulkInsert(IEnumerable Persons) { // use the information in the link to get your connection DbConnection conn = ... using (DbCommand cmd = conn.CreateCommand()) { var sb = new StringBuilder(); sb.Append("INSERT INTO person (firstname, lastname) VALUES "); var count = 0; foreach(var person in persons) { if (count !=0) sb.Append(","); sb.Append(GetInsertCommand(person, count++, cmd)); } if (count > 0) { cmd.CommandText = sb.ToString(); cmd.ExecuteNonQuery(); } } if (sb.Length > 0) ExecuteNonQuery(sb.ToString()); } private string GetInsertCommand(Person person, int count, DbCommand cmd) { var firstname = "@firstname" + count.ToString(); var lastname = "@lastname" + count.ToString(); cmd.Parameters.Add(firstname, person.Firstname); cmd.Parameters.Add(lastname, person.Firstname); return String.Format("({0},{1})", firstname, lastname); } 

我必须承认我没有对它进行过测试,但这应该是一种快速而肮脏的方法,可以绕过EF一些批量插入,直到批量插入是核心的一部分。

更新

只是一个快速的想法。 您是否尝试过迁移命名空间中的…方法? 也许这个批量插入,没有调查,但值得一试:

 private void BatchInsert(IEnumerable persons) { context.Persons.AddOrUpdate(persons); } 

我知道如果你定义一个像AddOrUpdate(p => p.Firstname, persons)这样的Key列AddOrUpdate(p => p.Firstname, persons)这个方法可能会很慢AddOrUpdate(p => p.Firstname, persons)但我猜不指定它,那应该是所有插入(不保证)

entity framework中有若干改进的机会:

组:

 yourContext.Configuration.AutoDetectChangesEnabled = false; yourContext.Configuration.ValidateOnSaveEnabled = false; 

在100个插入包中执行SaveChanges() …尝试使用1000并查看更改。

因为在所有这些插入期间,上下文是相同的,所以您可以每1000次插入重建上下文对象。 var yourContext = new YourContext();

在我的导入数据进程中进行此改进,从7分钟到6秒。

实际的数字……在你的情况下不可能是100的1000 …尝试并调整它。

您可以使用批量插入扩展名

用法:

 using EntityFramework.BulkInsert.Extensions; context.BulkInsert(myEntities); 

使用DbContext:

 using (var ctx = GetContext()) { using (var transactionScope = new TransactionScope()) { // some stuff in dbcontext ctx.BulkInsert(entities); ctx.SaveChanges(); transactionScope.Complete(); } } 

我担心EF不支持批量插入或更新。 正如您所说,EF目前会生成一堆Insert命令并单独执行它们(但所有这些命令都包含在一个事务中)。 有一些计划实施批处理,不确定最近是否有一些进展。 希望在EF6,但我不知何故怀疑。

您可以在此讨论中阅读更多内容 。

从存储库中插入ASP .NET Core版快速方法。

 public virtual void AddRangeFastAndCommit(IEnumerable entities) { MyDbContext localContext = new MyDbContext(_context.Options); localContext.ChangeTracker.AutoDetectChangesEnabled = false; foreach (var entity in entities) { localContext.Add(entity); } localContext.SaveChanges(); localContext.Dispose(); }