我有下表(表示为codefirst poco类)
Public Class JoinTable
Public Property ParentId as Integer
Public Property ChildId as Integer
End Class
现在我想制定一个要求,对于任何parentid,关联的childid都应该是唯一的。
所以,像parentid:1,childid:11这样的记录
父ID:1,子ID:12
父ID:2,子ID:11
是有效的,但是当我添加parentid:2,childid:12的记录时,这将是无效的,因为现在parentid 1和2具有相同的childid。
如何做到这一点(在sqlserver localdb上)?
可以使用实体框架来完成吗?
最佳答案
我将此视为“能否在数据库中建立/实施这样的关系”的一个挑战,并最终找到了这样做的方法。不过,我真的建议你不要这么做——那会很难看的。我当然不希望实体框架能够用它做任何智能的事情。
我们可以做的是显式地对子集合建模。我们创建一个特殊的空集合,然后通过添加一个大于该集合中当前最大元素的新元素,所有其他集合都必须从较小的集合派生。通过添加适当的唯一性约束,我们可以确保每一个集只能以一种方式派生,并且如果每个集都有一个可选的Parent
,则对于特定集只能有一个父集。
下面是数据库表:
create table Sets (
SetID uniqueidentifier not null
constraint DF_Set_IDs DEFAULT (newsequentialid()),
SubSetID uniqueidentifier null,
ParentID int null,
ElementValue int null,
SubsetElement int null,
constraint PK_Set PRIMARY KEY (SetID),
constraint UQ_Set_XRef UNIQUE (SetID,ElementValue),
constraint CK_Set_Empty CHECK (
(SetID = '00000000-0000-0000-0000-000000000000'
and ElementValue is null and SubSetID is null) or
(SetID <> '00000000-0000-0000-0000-000000000000'
and ElementValue is not null and SubSetID is not null)
),
constraint CK_Set_LargerElement CHECK (
SubsetElement < ElementValue
),
constraint FK_Set_SubSet FOREIGN KEY (SubSetID)
references Sets (SetID),
constraint FK_Set_SubSet_XRef FOREIGN KEY (SubSetID,SubsetElement)
references Sets (SetID,ElementValue),
constraint CK_Empty_Subsets CHECK (
(SubSetID = '00000000-0000-0000-0000-000000000000'
and SubsetElement is null) or
(SubSetID <> '00000000-0000-0000-0000-000000000000'
and SubSetElement is not null)
),
constraint UQ_SubSet_And_Current UNIQUE (SubSetID,ElementValue),
constraint FK_Set_Parent FOREIGN KEY (ParentID) references Parents (ParentID)
)
然后我们还需要一个过滤的唯一约束来确保父级只“拥有”一个集合:
create unique index UQ_OwnedSetParents on Sets (ParentID)
where ParentID is not null
所以,让我们依次考虑每个约束以及它给聚会带来的影响:
PK_Set
-此表的主键。我把a列设为uniqueidentifier
主要是为了使表中出现的int
与集合中的数字相关。UQ_Set_XRef
-跨越实际主键和ElementValue
值的“超级键”,允许外键在必要时检查两列。CK_Set_Empty
-我们只需要一个空集合,所以我们为该行的SetID
选择一个特殊值,然后确保它是唯一一个具有NULL
ElementValue
且不基于子集的集合。CK_Set_LargerElement
-我们要确保在构建集合时,每个集合的ElementValue
都大于它所基于的子集中的最大值。通过归纳,子集中最大的元素是子集的ElementValue
,下面是更多的元素。FK_Set_SubSet
-将此集合链接到它所基于的子集的外键FK_Set_SubSet_XRef
-这个外键确保我们在SubsetElement
中的值是该子集行的ElementValue
。CK_Empty_Subsets
-需要此检查,因为如果其中一列包含NULL
-则不检查外键引用,因此我们需要此检查来备份FK_Set_SubSet_XRef
并确保正确处理空集。UK_SubSet_And_Current
-这确保了对于任何给定的子集,最多有一个集合使用特定的元素值建立在它之上-这就是最终使每个集合唯一可表示的原因FK_Set_Parent
-这一点上的一个反极限-集合可以选择由父集合拥有UQ_OwnedSetParents
-这确保了每个家长最多只能“拥有”一个家长。正如您可能看到的,在这个表上操作会有些复杂。要枚举集合的成员,需要访问特定的集合,然后继续访问在其上生成每个成员的子集,直到到达空集合为止。
如果一个新的元素比任何现有元素都大,那么添加一个新元素是很简单的。添加一个更小的新元素要复杂得多,特别是如果其中一些子集是由其他父元素拥有的话。
关于sql-server - 是否可以创建约束以指定子表上的子集集不会针对主表上的不同父项重复?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24257852/