如何在EF6中定义多级唯一索引约束

时间:2019-02-04 18:12:42

标签: c# .net sql-server entity-framework entity-framework-6

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;}
}

这使我可以拥有一个名称,该名称对于给定的Factory是唯一的。但是,如果我每个区域都有多个工厂,并且由于某种原因,我想让一个部件在整个区域内具有唯一的名称,而不仅仅是工厂。结构将是Region-> Factory-> Part。由于Region不是Part的直接属性,我将如何为这种条件定义唯一索引?

编辑:由于似乎无法在EF6中定义,所以我愿意直接在sql server中进行操作。有人可以让我知道如何在sql server中做到这一点吗?

2 个答案:

答案 0 :(得分:1)

您要实现的目标是,Part实体在逻辑上必须知道其所属的Region,因为它的唯一性是由它定义的。那么,为什么不仅仅让Part也具有对Region的引用,并将该关系的键也用作唯一键的一部分呢?

答案 1 :(得分:1)

  

我想拥有一个在整个地区(而不仅仅是工厂)具有唯一名称的零件。 。 。   [并且]确保Part.Factory.Region.Id始终与Part.Region.Id相同,无论如何?

您输入Factory的密钥(RegionID,FactoryID)和Part的密钥(RegionID,FactoryID,PartID)。因此,Part是使用(RegionID,FactoryID)的外键引用Factory的。

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

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

直接在SQL Server(或Azure SQL数据库)中工作,可以在indexed view上创建唯一索引,也可以避免在Part上完全具有RegionID列。 EG:

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).