2013-06-24 57 views
23

我有一个实体列表,我想将它们插入到数据库中。如果实体已经存在于数据库中,那么它需要被跳过。如果它在数据库中但具有不同的值,则需要更新它。使用实体框架进行批量插入/更新的有效方法

有没有办法做到这一点,而不是每个项目做一个数据库调用?

我的计划是尝试一个插入,如果一个唯一的约束异常的关键是抛出然后做一个更新。

+0

[在实体框架中插入的最快方式]的可能重复(http://stackoverflow.com/questions/5940225/fastest-way-of-inserting-in-entity-framework) –

+0

这里是非常好的答案。 [http://stackoverflow.com/questions/5940225/fastest-way-of-inserting-in-entity-framework][1] [1]:HTTP://计算器。 com/questions/5940225 /插入实体框架的最快方式 –

回答

21

只是不要在这种情况下使用实体框架。只需使用存储过程(如何取决于您使用EF的版本/方法,您可能需要扩展您的DbContext或添加实体模型的映射)。

如果您使用的SQL Server,然后在你的存储过程,使用该MERGE命令有效不正是你需要:insert,如果它不存在,或者更新,如果它。一切都在一个高效的SQL查询中。

+0

如果使用SqlBulkCopy,它不能全部在单个查询中。它需要是一个sp来创建临时表,然后是一个sp来完成与中间的.net内容的合并。 –

+0

@IanWarburton为什么你需要'SqlBulkCopy'? SQL'Merge'命令可以满足您的所有需求。你可以通过传递你的实体作为参数来调用一个存储过程(例如表值参数),'Merge'将完成所有的工作。 – ken2k

+0

表值参数...是很酷。 –

9

EF不适用于BULK插页。 对于1000年的记录它可以,但大数字(100k加)它的速度慢。

如果您打算使用EF。

  • 试AddOrUpdate方法(而不是插入/更新)
  • 禁用跟踪,
  • 承诺每1000个记录或更少。

Context.Set<TPoco>().AddOrUpdate(poco); 
//... 
Context.Configuration.AutoDetectChangesEnabled = 
//.. 
Context.SaveChanges(); 

如果复制无关的数据,你可以尝试在平行(DOH)这些表

+0

我认为如果在批处理中存在唯一的约束异常,那将会很尴尬。 –

+0

如果您可能有许多独特的约束违规,那么批量提交的确不太有用。其实关于保存数据包的评论是建议你保持它们小,最大1000不太大。如果没有完整的腹部应付。如果吞吐量正常,请使用单个记录提交。您还可以尝试使用较小的数据包,例如10个,如果失败,则重试单个数据包。只是各种事情,我试图获得更好的吞吐量。 –

9

我已经为 https://efbulkinsert.codeplex.com/

的延伸,它是非常简单的使用

using(var context = new MyDbContext()) 
{ 
    context.BulkInsert(hugeCollectionOfEntities); 
} 
+5

只是抬头:这个库不支持导航属性。如果您有父/子表关联,插入后子表元素的外键将被设置为0 –

+3

这不处理事物的更新方面。 –

+0

它是免费的吗?或者我需要为它付费吗?。这是一样的http://entityframework-extensions.net/#pro? –

1
  1. 创建临时表: 的SqlCommand(的String.Format(“SELECT TOP 0 * INTO {0} FROM {1} ...

  2. 将数据批量插入到它中 - 上面提到的实体框架扩展需要进行调整以支持临时表名,但其他方面是正确的 - 或者滚动一些代码并使用SqlBulkCopy。

  3. 构造MERGE语句。

如果你是我的一个属性列表,你可以使(2)和(3)通用。我可以在大约20秒内读取并合并150,000行。

相关问题