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

EF Core如何按指定字段组合识别重复数据并阻止重复插入

EF Core 基于Name+Surname组合去重阻止重复入库实现方案

你的去重规则核心是Name和Surname两个字段组合全局唯一,和Citizenship字段取值无关,需要从「数据库约束兜底、EF Core配置、业务前置校验、并发异常处理」四个层面落地,彻底避免重复数据入库。

1. 配置复合唯一索引(最核心兜底方案)

这个方案会在数据库层面生成强唯一约束,就算应用层逻辑出现疏漏、或者高并发下出现竞态请求,数据库也会直接拒绝重复组合写入,是防重复的最可靠手段,必须配置。
在你的DbContext上下文类中重写OnModelCreating方法做如下配置:

public class AppDbContext : DbContext
{
    public DbSet<Person> Persons { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 配置Name+Surname复合唯一索引,可自定义索引名
        modelBuilder.Entity<Person>()
            .HasIndex(p => new { p.Name, p.Surname })
            .IsUnique()
            .HasDatabaseName("IX_Persons_Name_Surname_Unique");
    }
}

配置完成后执行EF Core迁移命令生成迁移脚本、更新数据库,唯一索引才会实际生效。

2. 插入前前置校验(提前拦截重复请求)

数据库兜底虽然可靠,但抛出异常会带来额外性能开销,正常流量下建议在业务逻辑层先做一次重复校验,提前拦截重复请求:

public async Task<(bool Success, string Msg)> AddPersonAsync(Person newPerson, CancellationToken ct)
{
    // 校验是否已存在同Name+Surname的记录
    bool existsDuplicate = await _dbContext.Persons
        .AnyAsync(p => p.Name == newPerson.Name && p.Surname == newPerson.Surname, ct);
    
    if (existsDuplicate)
    {
        // 可根据业务需求直接返回错误、记录日志或抛自定义业务异常
        return (false, "已存在相同姓名的人员记录,不可重复添加");
    }

    _dbContext.Persons.Add(newPerson);
    await _dbContext.SaveChangesAsync(ct);
    return (true, string.Empty);
}

3. 并发场景异常捕获处理

高并发场景下可能出现两个请求同时通过前置校验、同时执行插入的竞态情况,这时候数据库唯一索引会抛出更新异常,需要单独捕获处理,避免程序直接报错:

public async Task<(bool Success, string Msg)> SavePersonWithCheckAsync(Person newPerson, CancellationToken ct)
{
    try
    {
        _dbContext.Persons.Add(newPerson);
        await _dbContext.SaveChangesAsync(ct);
        return (true, string.Empty);
    }
    catch (DbUpdateException ex) when (IsUniqueIndexConflict(ex))
    {
        // 捕获唯一索引冲突异常,判定为重复数据
        return (false, "已存在相同姓名的人员记录,不可重复添加");
    }
}

// 适配不同数据库的唯一约束冲突错误码
private bool IsUniqueIndexConflict(DbUpdateException ex)
{
    var errorCode = ex.InnerException switch
    {
        Microsoft.Data.SqlClient.SqlException sqlEx => sqlEx.Number,
        Npgsql.PostgresException pgEx => int.Parse(pgEx.SqlState),
        MySqlConnector.MySqlException mysqlEx => mysqlEx.Number,
        _ => 0
    };

    return errorCode switch
    {
        2601 or 2627 => true, // SQL Server 唯一索引/约束冲突错误码
        23505 => true, // PostgreSQL 唯一冲突错误码
        1062 => true, // MySQL 唯一冲突错误码
        _ => false
    };
}

注意事项

  • 不要只靠应用层校验做去重,没有数据库唯一索引兜底的话,高并发下一定会出现重复数据
  • 如果需要做大小写不敏感的姓名去重,可以在配置索引时指定对应排序规则,比如SQL Server环境下追加.UseCollation("SQL_Latin1_General_CP1_CI_AS")即可
  • 后续如果调整去重规则,只需要修改唯一索引对应的字段组合,重新生成迁移更新数据库即可

内容的提问来源于stack exchange,提问作者Chris Claude

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 03:45:47