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

EF Core中基于条件实现Upsert(存在更新不存在插入)的方案咨询

问题根因

你生成的SQL本身逻辑是符合MySQL的Upsert语法的,但ON DUPLICATE KEY UPDATE机制只有在插入操作触发主键/唯一键冲突时才会执行更新逻辑。你当前场景下UserName和Key两个字段没有配置联合唯一索引,数据库不会判定插入的记录重复,所以会一直插入新行。

修复步骤

1. 给实体配置联合唯一索引

在你的DbContext的OnModelCreating方法中添加索引约束,之后执行EF Core迁移将规则同步到数据库:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<UserStateEntity>()
        .HasIndex(u => new { u.UserName, u.Key })
        .IsUnique(); // 必须指定唯一约束才会触发冲突判定
}

2. 修正FlexLabs.Upsert的使用代码

你的原有代码存在两个冗余/错误点:

  • RunAsync()方法本身已经包含提交逻辑,不需要额外调用SaveChangesAsync()
  • 实体类型对应错误,你定义的实体是UserStateEntity,更新语句中错误使用了UserDataEntity

修正后代码如下:

public async Task UpdateStateAsync()
{
    var userData = new UserStateEntity
    {
        UserName = "123",
        Key = "456",
        Value = "MainMenu"
    };
        
    await dbContext
        .UserCache // 和你DbSet定义的属性名保持一致
        .Upsert(userData)
        .On(ud => new {ud.UserName, ud.Key})
        .WhenMatched(v => new UserStateEntity {Value = userData.Value})
        .RunAsync();
}

无第三方依赖的原生EF Core实现方案

如果你不想引入FlexLabs.Upsert库,可以在加了唯一索引的前提下,用事务+异常捕获优化原有实现,解决并发场景下的重复插入问题:

public async Task AddCacheValueAsync(string userName, string key, string value)
{
    using var transaction = await dbContext.Database.BeginTransactionAsync();
    try
    {
        var existedData = await dbContext.UserCache
            .SingleOrDefaultAsync(d => d.UserName == userName && d.Key == key);
        if (existedData != null)
        {
            existedData.Value = value;
        }
        else
        {
            dbContext.UserCache.Add(new UserStateEntity
            {
                UserName = userName,
                Key = key,
                Value = value
            });
        }
        await dbContext.SaveChangesAsync();
        await transaction.CommitAsync();
    }
    catch (DbUpdateException)
    {
        // 并发插入冲突时重试更新逻辑
        var existedData = await dbContext.UserCache
            .SingleAsync(d => d.UserName == userName && d.Key == key);
        existedData.Value = value;
        await dbContext.SaveChangesAsync();
        await transaction.CommitAsync();
    }
}

内容的提问来源于stack exchange,提问作者Vadim Martynov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 09:06:06