如何在C#中使属性唯一?以City类Name属性为例
实现City类Name属性唯一性的方案
1. 数据库层面添加唯一约束(最可靠)
数据库约束是防止重复数据的最后一道防线,无论通过何种方式操作数据,数据库都会拦截重复值。
用EF Core Fluent API配置
如果使用Entity Framework Core,可在DbContext的OnModelCreating方法中配置唯一索引:
protected override void OnModelCreating(ModelBuilder modelBuilder) { // 基础唯一索引配置 modelBuilder.Entity<City>() .HasIndex(c => c.Name) .IsUnique() .HasDatabaseName("IX_Cities_Name"); // 若需忽略大小写(如"Beijing"和"beijing"视为重复),针对不同数据库适配: // SQL Server 配置不区分大小写的排序规则 modelBuilder.Entity<City>() .HasIndex(c => c.Name) .IsUnique() .HasDatabaseName("IX_Cities_Name") .HasCollation("SQL_Latin1_General_CP1_CI_AS"); // PostgreSQL 可改用citext类型实现大小写不敏感 // modelBuilder.Entity<City>() // .Property(c => c.Name) // .HasColumnType("citext"); // 再配置唯一索引 }
手动创建数据库约束(非EF场景)
直接执行SQL语句添加约束:
-- SQL Server CREATE UNIQUE NONCLUSTERED INDEX IX_Cities_Name ON Cities (Name COLLATE SQL_Latin1_General_CP1_CI_AS); -- PostgreSQL CREATE UNIQUE INDEX IX_Cities_Name ON Cities (LOWER(Name)); -- MySQL CREATE UNIQUE INDEX IX_Cities_Name ON Cities (Name) COLLATE utf8mb4_general_ci;
2. 业务逻辑层提前校验
在添加/更新City对象前,先查询数据库是否存在同名记录,避免触发数据库异常:
public async Task<bool> AddCityAsync(City newCity) { // 检查是否存在同名城市,支持大小写忽略 var existingCity = await _dbContext.Cities .FirstOrDefaultAsync(c => c.Name.Equals(newCity.Name, StringComparison.OrdinalIgnoreCase)); if (existingCity != null) { throw new InvalidOperationException($"名称为{newCity.Name}的城市已存在"); // 也可返回false,由上层处理错误逻辑 // return false; } _dbContext.Cities.Add(newCity); await _dbContext.SaveChangesAsync(); return true; }
3. 数据注解方式(EF Core有限支持)
.NET 5+支持用[Index]注解快速配置,但灵活性不如Fluent API:
public class City: MyClass1 { [MaxLength(255)] [Index(IsUnique = true, Name = "IX_Cities_Name")] public required string Name { get; set; } }
注:此方式无法直接配置大小写不敏感,仍推荐使用Fluent API。
4. 并发场景处理
多请求同时添加同名城市时,业务层校验可能出现竞态条件,需捕获数据库唯一约束异常并处理:
public async Task<bool> AddCityAsync(City newCity) { try { _dbContext.Cities.Add(newCity); await _dbContext.SaveChangesAsync(); return true; } catch (DbUpdateException ex) { // 针对SQL Server的唯一约束错误码(2601)做判断 if (ex.InnerException is SqlException sqlEx && sqlEx.Number == 2601) { throw new InvalidOperationException($"名称为{newCity.Name}的城市已存在", ex); } throw; // 其他异常重新抛出 } }
内容的提问来源于stack exchange,提问作者Czesław Nowicki
相关产品推荐
相关产品推荐

