You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor中SQLite触发唯一约束异常后,后续插入均报错问题

问题原因与解决方案

问题根源

当SaveChangesAsync因唯一约束抛出异常时,导致冲突的实体仍然被EF Core的ChangeTracker跟踪着。后续调用AddObjectAsync插入新实体时,DbContext会尝试提交所有被跟踪的待插入实体(包括之前冲突的那个),哪怕新实体合法,也会因为旧冲突实体的存在再次触发唯一约束异常。重启程序后DbContext被重建,跟踪的实体清空,因此恢复正常。

修复方案

方案1:捕获异常后移除冲突实体

在catch块中将冲突实体从DbContext的跟踪中移除,避免后续操作重复提交它:

public async Task<MyObject> AddObjectAsync(MyObject myObject)
{
    try
    {
        dbContext.MyObjects.Add(myObject);
        await dbContext.SaveChangesAsync();
    }
    catch (Exception ex)
    {
        if (ex.InnerException is SqliteException sqliteEx && sqliteEx.SqliteErrorCode == 19)
        {
            // 解除冲突实体的跟踪状态
            dbContext.Entry(myObject).State = EntityState.Detached;
            throw new SqliteException(sqliteEx.Message, sqliteEx.SqliteErrorCode);
        }
        else throw;
    }
    return myObject;
}

方案2:使用短生命周期DbContext

如果当前DbContext是单例或长生命周期,改为每个操作/请求创建新的DbContext实例(比如依赖注入中配置为Scoped)。这样每次插入操作都用全新的DbContext,不存在旧实体残留问题:

// 示例:通过依赖注入获取Scoped生命周期的DbContext,或直接创建新实例
public async Task<MyObject> AddObjectAsync(MyObject myObject)
{
    using var dbContext = new MyDbContext();
    try
    {
        dbContext.MyObjects.Add(myObject);
        await dbContext.SaveChangesAsync();
    }
    catch (Exception ex)
    {
        if (ex.InnerException is SqliteException sqliteEx)
        {
            throw new SqliteException(sqliteEx.Message, sqliteEx.SqliteErrorCode);
        }
        else throw;
    }
    return myObject;
}

额外注意

  • 不要复用同一个DbContext实例处理多次数据库操作,异常后ChangeTracker状态极易混乱。
  • 可通过SQLite错误码(19对应唯一约束冲突)做精准处理,避免误清理其他异常场景的实体。

内容的提问来源于stack exchange,提问作者Christophe CGE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 22:52:39