使用 EF6 执行 UPSERT 的更有效方法

Nug*_*ugs 4 c# entity-framework-6

我有以下代码块,它基本上检查数据库中实体的存在并将其加载到上下文以进行更新,或者在它不存在的情况下添加新实体。

using (var db = new Entities.DB.DConn())
{
    //...
    foreach (Account account in accounts)
    {
        bool isNewRecord = false;
        Entities.DB.Account dlAccount = new Entities.DB.Account();
        Entities.DB.Account exisitngAcct = db.Accounts.Where(x => x.GId == dlG.Id).FirstOrDefault(); //x.GId is NOT ad primary key
        if (exisitngAcct != null)
        {
            dlAccount = exisitngAcct;
            isNewRecord = true;
        }

        dlAccount.GId = dlG.Id;
        dlAccount.AccountName = account.NameAtFI;
        dlAccount.AccountNumber = account.AcctNumber;
        dlAccount.AcctType = account.AcctType;
        dlAccount.AsOfDate = account.DateCreated;
        dlAccount.IsDeleted = false;
        dlAccount.DateModified = DateTime.UtcNow.ToUniversalTime();

        if (isNewRecord)
        {
            dldb.Accounts.Add(dlAccount);
        }

        db.SaveChanges();
    }
}
Run Code Online (Sandbox Code Playgroud)

我一直在对将实体附加到上下文和使用 EntityState 进行大量研究,但我只是不知道如何在我的示例中编写该代码。

有什么办法可以帮助我向我展示一种更好、更有效的方法来执行与上述相同的操作?我对 EF 还很陌生,想确保我能正确使用它。

感谢您的任何帮助,您可以提供。

Iva*_*oev 5

EF 的设计者已将使用断开连接的实体留给使用它的开发人员。因此没有“正确”的方式——一切都取决于用例和实体模型。

由于您似乎在强制更新现有记录(通过设置DateModified),因此无需将现有数据加载到上下文中。使用单个数据库行程获取现有实体 PK 并将其用作添加或更新的标准就足够了:

using (var db = new Entities.DB.DConn())
{
    //...
    var accountIds = accounts.Select(x => x.GId); // variable required by EF6 Contains translation
    var existingAccountIds = new HashSet<GId_Type>(
        db.Accouns.Where(x => accountIds.Contains(x.GId).Select(x => x.GId));
    foreach (Account account in accounts)
    {
        var dlAccount = new Entities.DB.Account();
        dlAccount.GId = account.GId;
        dlAccount.AccountName = account.NameAtFI;
        dlAccount.AccountNumber = account.AcctNumber;
        dlAccount.AcctType = account.AcctType;
        dlAccount.AsOfDate = account.DateCreated;
        dlAccount.IsDeleted = false;
        dlAccount.DateModified = DateTime.UtcNow.ToUniversalTime();    
        if (existingAccountIds.Contains(dlAccount.GId))
            db.Entry(dlAccount).State = EntityState.Modified; // update
        else
            db.Accounts.Add(dlAccount); // insert
    }
    db.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)

(将 替换为GId_Type的类型GId,例如intGuid等)

这一点,连同SaveChanges将循环移到外部,应该为您提供这种情况下的最佳性能。