首页 > 解决方案 > 如何在 EF6 中定义多级唯一索引约束

问题描述

EF 允许我们在多个属性上定义唯一索引约束,如下所示:

public class Part 
{
        public int Id { get; set; }
        [Index("IX_Name_Factory", Order = 1, IsUnique = true)]
        public string Name {get;set;}
        [Required]
        public Factory Factory { get; set; }
        [ForeignKey("Factory"), Index("IX_Name_Factory", Order = 2, IsUnique = true)]
        public int Factory_Id {get;set;}
}

这使我可以拥有一个名称对于给定工厂来说是唯一的零件。但是,如果我每个地区有多个工厂,并且出于某种原因,我想要一个名称在整个地区都独一无二的零件,而不仅仅是一个工厂,该怎么办。结构将是区域 -> 工厂 -> 零件。由于 Region 不是 Part 的直接属性,我将如何为这种条件定义唯一索引?

编辑:因为这似乎无法在 EF6 中定义,所以我愿意直接在 sql server 中进行定义。有人可以让我知道如何在 sql server 中执行此操作吗?

标签: c#.netsql-serverentity-frameworkentity-framework-6

解决方案


我想要一个名称在整个地区都独一无二的零件,而不仅仅是一家工厂。. . [并且] 确保 Part.Factory.Region.Id 始终与 Part.Region.Id 相同?

您制作工厂的密钥(RegionID,FactoryID)和零件的密钥(RegionID,FactoryID,PartID)。所以 Part 是指使用(RegionID,FactoryID)外键的工厂。

这将确保零件的 RegionID 始终与零件的工厂的 RegionID 相同。

然后,要使 Part.Name 在区域内唯一,请在 Part (RegionID,Name) 上添加唯一索引。

直接在 SQL Server(或 Azure SQL 数据库)中工作,您可以在索引视图上创建唯一索引,并且还可以完全避免在 Part 上使用 RegionID 列。例如:

use tempdb

go
drop table if exists Part
drop table if exists Factory
drop table if exists Region 
go

create table Region(RegionID int primary key);
create table Factory(FactoryID int primary key, RegionID int references Region);
create table Part(PartID int primary key, FactoryID int references Factory, Name varchar(200));

go

create view vRegionPartName
with schemabinding
as
select r.RegionID, p.Name PartName
from dbo.Region r
join dbo.Factory f
  on r.RegionID = f.RegionID
join dbo.Part p 
  on p.FactoryID = f.FactoryID

go

create unique clustered index pk_vRegionPartName
on vRegionPartName(RegionID,PartName)

go

insert into Region(RegionID) values (1)
insert into Factory(FactoryID,RegionID) values (1,1)
insert into Factory(FactoryID,RegionID) values (2,1)
insert into Part(PartID,FactoryID,Name) values (1,1,'Part1')

insert into Part(PartID,FactoryID,Name) values (2,2,'Part1')
--fails with
--Msg 2601, Level 14, State 1, Line 36
--Cannot insert duplicate key row in object 'dbo.vRegionPartName' with unique index 'pk_vRegionPartName'. The duplicate key value is (1, Part1).

推荐阅读