如何建模两个Access实体匹配并避免反向重复组合?
解决AccessMatch无序配对的唯一约束问题
要禁止(10,20)和(20,10)这类重复配对,可以从业务逻辑或数据库约束两个层面入手,以下是具体方案:
方案一:业务层强制ID顺序
在创建AccessMatch实例时,强制让Access1Id始终小于Access2Id,确保同一对Access不管传入顺序如何,都以固定顺序存储。这样原来的唯一索引就能直接生效。
修改AccessMatch的构造逻辑:
public class AccessMatch { public int Id { get; private set; } public string Name { get; private set; } protected internal int Access1Id { get; private set; } public Access Access1 { get; private set; } protected internal int Access2Id { get; private set; } public Access Access2 { get; private set; } public AccessMatch(Access access1, Access access2) { if (access1.Id == access2.Id) throw new ArgumentException("不允许将同一个Access与自身配对"); // 强制小ID在前,大ID在后 if (access1.Id < access2.Id) { Access1 = access1; Access1Id = access1.Id; Access2 = access2; Access2Id = access2.Id; } else { Access1 = access2; Access1Id = access2.Id; Access2 = access1; Access2Id = access1.Id; } } }
方案二:数据库层面添加计算列唯一索引
如果不想修改业务逻辑,可以在数据库中通过计算列生成两个ID的有序值,再对这两个计算列添加唯一约束。以EF Core + SQL Server为例:
// 定义计算列:取两个ID中的较小值 builder.Property<int>("SmallerId") .HasComputedColumnSql("LEAST(Access1Id, Access2Id)") .HasColumnType("int"); // 定义计算列:取两个ID中的较大值 builder.Property<int>("LargerId") .HasComputedColumnSql("GREATEST(Access1Id, Access2Id)") .HasColumnType("int"); // 为计算列添加唯一索引 builder.HasIndex("SmallerId", "LargerId").IsUnique();
这样无论Access1Id和Access2Id的顺序如何,数据库都会基于排序后的两个值做唯一校验,阻止重复配对。
注意事项
如果数据库中已有历史数据,需要先将所有AccessMatch记录更新为Access1Id <= Access2Id的格式,再应用上述约束,否则会触发唯一键冲突。
内容的提问来源于stack exchange,提问作者dhrm
相关产品推荐
相关产品推荐

