稍微概述一下我想要完成的事情。 我们在应用程序中保留远程数据库(第三方)的本地副本。要下载信息,我们使用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();
}
这很好用,但感觉这可以改善。
关于如何改善这一点的任何建议都会很棒。我仍然是c#的新手,所以我仍然在寻找最好的办法。
我正在使用.net 4.5.2和Entity Framework 6.1.3以及MSSQL 2014作为后端数据库
答案 0 :(得分:5)
if
来更新现有实体。对于批量插入,我使用Attach(newAccount, originalAccount)
。如果您要插入大量实体,建议批量处理它们。此外,您可能希望在每个批次上处置并重新创建AddRange(listOfNewEntitities)
,以便它不会占用太多内存。
DbContext
对于批量更新,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的性能。
因此,在10,000个实体中,Add方法在上下文中添加实体的时间增加了875倍。
修复它:
在您的情况下,您需要为存储库创建一个InsertRange方法。
EF扩展
你是对的。该库使用相同的值更新所有数据。那不是你想要的。
免责声明:我是该项目的所有者Entity Framework Extensions
如果您希望显着提高性能,此库可能非常适合您的企业。
您可以轻松执行:
示例:
public void ProcessApiData(List<Account> apiData)
{
// Insert or Update using the primary key (AccountID)
CurrentUnitOfWork.BulkMerge(apiData);
}