0

我正在编写一个小应用程序来管理菜单的元数据。AMenu附加到一个App,并且也(可选地)附加到另一个Menu(因此定义了一个子菜单)。所以接线是这样的:附加到Menu.AppIdApp.Id然后定义子菜单。Menu.ParentIdMenu.Id

但这可以让我插入不连贯的数据:

INSERT INTO Menu (Id, ParentId, AppId, Desc) values (1, NULL, 25, 'Top Menu')
INSERT INTO Menu (Id, ParentId, AppId, Desc) values (2, 1, 36, 'Sub Menu')

这里我只是说App #36的Sub Menu应该在App #25(另一个 App)的Top Menu下。

有没有一种方法可以定义约束以确保当我将Sub Menu作为Top Menu的子项插入时,应用程序必须是#25(触发器不是一个选项)?

(当然我会在用户界面中管理它,但我也在寻找一种方法来保护模型)。

谢谢,

4

2 回答 2

1

您可以使用外键约束

第一个约束(Id, AppId)是唯一的(如果Id是 PK 很明显,但需要检查以下 FK 约束):

alter table Menu add constraint unique_app unique (Id, AppId)

然后约束一个孩子有相同的AppId

alter table Menu add constraint fk_same_parent_app
foreign key (ParentId, AppId) references Menu(Id, AppId)

编辑:如果您需要更改 AppId,则必须为层次结构中的每个菜单一次完成。这可以通过使用 CTE 的递归查询来完成:

with AMenu(Id, ParentId)
as (
  -- start with a root
  select Id, ParentId
  from Menu where Id = <id_of_a_root>
union all 
  -- recursively add children
  select m.Id, m.ParentId
  from Menu m 
  join Amenu am on m.ParentId = am.Id
)
update m
set AppId = <some_value>
from Menu m 
join AMenu am 
on m.Id = am.Id
于 2013-08-20T13:48:23.727 回答
0

好的,我有一个方法,但它需要你让 appid 允许空值。在这种情况下,appid 只会在父级中。

create table #temp (parentid int null,  appid int NUll)
ALTER TABLE #temp
ADD CONSTRAINT myconstraint CHECK (parentid+appid = Null and (isnull(parentid, 0)+isnull(appid,0) = parentid  or isnull(parentid, 0)+isnull(appid,0) = appid));

insert #temp
values(1,null)
insert #temp
values(null,1)
insert #temp
values(1,1)

我不知道那种结构对你有用,但这是我能想到的唯一方法来提出一个工作检查约束。

于 2013-08-20T13:32:17.893 回答