2013-06-24 52 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行。

相關問題