2012-02-24 59 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