2012-02-24 43 views
0

我使用AutoMapper從舊的數據庫對象映射到EF代碼首先聲明瞭一個新的數據庫:提高在種子中初始化DbSet的性能?

StartTimer("Map Customers");  
     var mfpCustomers = Mapper.Map<IEnumerable<LegacyDataModel.Customer>, IEnumerable<Customer>>(
     legacyEntities.Customers.Include(p => p.Demographics).ToList()); 
     StopAndPrintTimer("Map Customers"); 

     StartTimer("Iterate Customers"); 
     foreach (var p in mfpCustomers) 
     { 
     db.Customers.Add(p);  
     } 
     StopAndPrintTimer("Iterate Customers"); 

的每個是什麼花費最多的時間。我想直接映射到DbSet(db.Customer),而不是通過db.Customers.Add(p);做一個foreach。我還沒有想出如何做到這一點,因爲沒有什麼像專門爲添加大量對象而設計的AddRange方法。我知道如何在SQL中使用基於集合的技術來完成這些類型的轉換,但這是一種瘋狂的打字量,因爲智能感知在SSMS中的這些情景中不起作用。

這段代碼並不需要超快速,但是每次我種下數據庫時都要等上一整分鐘,這使得開發變得困難(並且由於新數據庫的快速開發,它確實需要經常重新調整) 。還要注意,由於這是種子方法,我不介意完全取代現有的客戶(因爲沒有)。所以在這方面它不需要表現得像AddRange,因爲我真的只是創建一個新的集合。

有關如何在此提高性能的任何想法? 關於如何將整個集合直接映射到DbSet而不對每個實例進行foreach的任何想法?

回答

1

每次調用db.Customers.Add(p)時,EF都會進行DetectChanges調用,以查看實體圖中是否有任何內容發生更改。當對其他實體進行更改後調用Add時,這有助於使事情按預期工作。但是,如果上下文中有很多實體,則DetectChanges可能會變慢 - 它在實體數量上具有O(n)個時間。因此,如果您有這種情況,您可以暫時將這些自動呼叫轉到DetectChanges,這會產生很大的影響。例如:

try 
{ 
    context.Configuration.AutoDetectChangesEnabled = false; 

    foreach (var p in mfpCustomers) 
    { 
     db.Customers.Add(p);   
    } 
} 
finally 
{ 
    context.Configuration.AutoDetectChangesEnabled = true; 
} 

你可以在這裏找到更多的細節: http://blogs.msdn.com/b/adonet/archive/2011/02/06/using-dbcontext-in-ef-feature-ctp5-part-12-automatically-detecting-changes.aspx

+0

這是偉大的。如果我在自動檢測恢復爲真前調用SaveChanges,它似乎會更快。它是否可以正確保存或以任何理由先於另一個?在實現這個之後,我注意到一些奇怪的地方,即使我使用了DropCreateDatabaseAlways,我的初始化程序根本沒有被調用。我實際上必須清理並重建項目,以強制它調用我的種子函數。 – AaronLS 2012-02-27 19:08:20

+0

在這種情況下,如果您在再次切換DetectChanges之前調用SaveChanges,它應該保存得很好。如果您在添加它們並調用SaveChanges之間做任何其他操作,則可能無法正確保存。 – 2012-02-27 19:41:44