首页 > 解决方案 > 已删除实体上的 SaveChanges 引发 DuplicateKeyException

问题描述

我创建一个实体对象并将其存储在数据库中。然后,我创建第二个具有相同 PrimaryKey 值(来自时间戳和 id 列)但内容不同的第二个。将此添加到 DbContext 会引发“InvalidOperationException”,因此我抓住了它并执行了context.Update(obj). 现在SaveChanges()抛出“DbUpdateException”,其中 InnerException 显示“DuplicateKeyException”,但对象状态为“已修改”。

此时,我尝试删除旧记录并存储新记录,但SaveChanges(true)context.Remove(obj).

我尝试通过两个SaveChanges(true)调用在单独的事务中执行此操作,但第一个失败。

在 StackOverflow 和 MS 文档中都没有找到解决方案。

这里有一些示例“相似”代码:

// Example Model-Class
public partial class MyEntity
{
    public DateTime Timestamp { get; set; } // this and ...
    public int id { get; set; }             // this is the PrimaryKey in DB and DbContext classes
    public String Data { get; set;}
}
:
:
// Do the work somewhere
MyEntity entity1 = CreateEntity(new DateTime(2020,1,1,0,0,0), 1, "Ape");
SaveMyStuff(entity1, false);

MyEntity entity2 = CreateEntity(new DateTime(2020,1,1,0,0,0), 1, "Ape");
try {
    SaveMyStuff(entity2. false);
}catch(InvalidOperationException iOpEx)
{ /* Expected this, so do nothing */ }

MyEntity entity3 = CreateEntity(new DateTime(2020,1,1,0,0,0), 1, "Monkey");
SaveMyStuff(entity3, true); // <-- FAIL
:
:

public void SaveMyStuff(MyEntity entity, bool Overwrite)
{
    MyDbContext context = serviceProvider.GetRequiredService<MyDbContext>(); // via AddDbContextPool()
    try {
        context.Add(entity);
    }catch (InvalidOperationException iOpEx)
    {
        if( Overwrite )
        {
            // If the context already know entity's primary keys, do a update instead
            context.Update(entity);
        }
        else
            throw iOpEx;
    }
    try {
        context.SaveChanges(true);
    }catch(Microsoft.EntityFrameworkCore.DbUpdateException dbUpdEx)
    {
        if( Overwrite )
        {
            using (TransactionScope scope = new TransactionScope())
            {
                context.Remove(entity);
                context.SaveChanges(true); // <-- throws DuplicateKeyException
                context.Add(entity);
                context.SaveChanges(true);
                scope.Complete();
            }
        }
        else
            throw dbUpdEx;
    }
}

我是否错过了一些模式或如何做这些事情?

标签: c#entity-framework-core

解决方案


推荐阅读