实体框架更新/插入多个实体

时间:2016-09-23 09:01:52

标签: c# sql-server entity-framework

稍微概述一下我想要完成的事情。 我们在应用程序中保留远程数据库(第三方)的本地副本。要下载信息,我们使用api。 我们目前按计划下载信息,然后将新记录插入本地数据库或更新现有记录。 这是它目前的工作方式

public void ProcessApiData(List<Account> apiData)
{
     // get the existing accounts from the local database
     List<Account> existingAccounts = _accountRepository.GetAllList();

     foreach(account in apiData)
     {
         // check if it already exists in the local database
         var existingAccount = existingAccounts.SingleOrDefault(a => a.AccountId == account.AccountId);

         // if its null then its a new record
         if(existingAccount == null)
         {
             _accountRepository.Insert(account);
             continue;
         }

         // else its a new record so it needs updating
         existingAccount.AccountName = account.AccountName;

         // ... continue updating the rest of the properties
     }

     CurrentUnitOfWork.SaveChanges();
}

这很好用,但感觉这可以改善。

  1. 每个实体都有这些方法之一,它们都做同样的事情(只是更新不同的属性)或插入不同的实体。无论如何都会使这更通用吗?
  2. 看起来好像很多数据库调用,无论如何都要“Bulk”这样做。我已经看过这个包,我在其他几篇文章https://github.com/loresoft/EntityFramework.Extended中看过 但它似乎专注于批量更新具有相同值的单个属性,或者我可以说。
  3. 关于如何改善这一点的任何建议都会很棒。我仍然是c#的新手,所以我仍然在寻找最好的办法。

    我正在使用.net 4.5.2和Entity Framework 6.1.3以及MSSQL 2014作为后端数据库

3 个答案:

答案 0 :(得分:5)

  1. 假设apiData中的类与您的实体相同,您应该能够使用if来更新现有实体。
  2. 对于批量插入,我使用Attach(newAccount, originalAccount)。如果您要插入大量实体,建议批量处理它们。此外,您可能希望在每个批次上处置并重新创建AddRange(listOfNewEntitities),以便它不会占用太多内存。

    DbContext
  3. 对于批量更新,LINQ to SQL中没有内置任何内容。然而,有一些库和解决方案来解决这个问题。参见例如Here表示使用表达式树的解决方案。

答案 1 :(得分:5)

对于EFCore,您可以使用此库:
https://github.com/borisdj/EFCore.BulkExtensions

对于EF 6这一个:
https://github.com/TomaszMierzejowski/EntityFramework.BulkExtensions

两者都使用批量操作扩展DbContext并具有相同的语法调用:

context.BulkInsert(entitiesList);
context.BulkUpdate(entitiesList);
context.BulkDelete(entitiesList);

EFCore版本还有BulkInsertOrUpdate方法。

答案 2 :(得分:2)

列表与词典

每次检查实体是否存在时,您都会检入列表。您应该创建一个字典来改善性能。

var existingAccounts = _accountRepository.GetAllList().ToDictionary(x => x.AccountID);

Account existingAccount;

if(existingAccounts.TryGetValue(account.AccountId, out existingAccount))
{
    // ...code....
}

添加与AddRange

添加多条记录时,您应该了解Add vs. AddRange的性能。

  • 添加:添加每条记录后调用DetectChanges
  • AddRange:添加所有记录后调用DetectChanges

enter image description here

因此,在10,000个实体中,Add方法在上下文中添加实体的时间增加了875倍。

修复它:

  1. 创建列表
  2. 将实体添加到列表
  3. 使用列表
  4. 的AddRange
  5. 的SaveChanges
  6. 完成!
  7. 在您的情况下,您需要为存储库创建一个InsertRange方法。

    EF扩展

    你是对的。该库使用相同的值更新所有数据。那不是你想要的。

    免责声明:我是该项目的所有者Entity Framework Extensions

    如果您希望显着提高性能,此库可能非常适合您的企业。

    您可以轻松执行:

    • BulkSaveChanges
    • BulkInsert
    • BulkUpdate
    • BulkDelete
    • BulkMerge

    示例:

    public void ProcessApiData(List<Account> apiData)
    {
        // Insert or Update using the primary key (AccountID)
        CurrentUnitOfWork.BulkMerge(apiData);
    }