我目前正在使用SQLAzure。
我正在设置一个设计,每个用户都有一些地址
当用户然后下订单时,我想将该订单链接到用户和几个地址。
所以我的表格如下:
用户
- 编号
- 名称
- 等
地址
- 编号
- UserId(外键)
- 街
- 等
顺序
- 编号
- UserId(外键)
- DeliveryAddressId(外键)
- BillingAddressId(外键)
- 等
有没有办法我可以在SQL Server中设置一个检查,以便用户在任何情况下都不能(例如通过黑客攻击HTML POST)提交一个带有AddressId的订单,该订单没有链接到与提交了UserId。我看过文档中的“外键约束”,但这似乎并不是我想要的。
任何关于尝试什么的建议 - 或者要阅读的教程 - 都会受到最高的赞赏。
答案 0 :(得分:3)
除了地址表中的主键(在Id上),还应该在(Id,UserId)上声明另一个键约束,UNIQUE约束。
ALTER TABLE Address ADD CONSTRAINT UQ_Address_UserCheck UNIQUE (Id,UserID)
然后,您可以将订单中的现有FK替换为地址,或添加其他FK,以检查两列
ALTER TABLE Order ADD CONSTRAINT
FK_Order_DeliveryAddress_UserCheck FOREIGN KEY (DeliveryAddressID,UserID)
references Address (Id,UserId)
正如我所说,如果你愿意,你可以将这些全部添加为附加约束。
因此,通过一些轻微的命名调整,您的表格将呈现为:
create table Users (
UserID int IDENTITY(1,1) not null,
Name varchar(30) not null,
/* Other columns */
constraint PK_Users PRIMARY KEY (UserID),
constraint UQ_User_Names UNIQUE (Name)
)
go
create table Addresses (
AddressID int IDENTITY(1,1) not null,
UserID int not null,
Street varchar(35) not null,
/* Other columns */
constraint PK_Addresses PRIMARY KEY (AddressID),
constraint FK_Addresses_Users FOREIGN KEY (UserID) references Users (UserID),
constraint UQ_Addresses_UserCheck UNIQUE (UserID,AddressID)
)
go
create table Orders (
OrderID int IDENTITY (1,1) not null,
UserID int not null,
DeliveryAddressID int not null,
BillingAddressID int not null,
/* Other columns - there may be other nullability concerns above */
constraint PK_Orders PRIMARY KEY (OrderID),
constraint FK_Orders_Users FOREIGN KEY (UserID) references Users (UserID),
constraint FK_Orders_DeliveryAddresses FOREIGN KEY (DeliveryAddressID) references Addresses (AddressID),
constraint FK_Orders_BillingAddresses FOREIGN KEY (BillingAddressID) references Addresses (AddressID),
/* Further constraints - ensure UserID -> AddressID match */
constraint FK_Orders_DeliveryAddress_UserCheck FOREIGN KEY (UserID,DeliveryAddressID) references Addresses (UserID,AddressID),
constraint FK_Orders_BillingAddress_UserCheck FOREIGN KEY (UserID,BillingAddressID) references Addresses (UserID,AddressID)
)
尝试使用一些应该可以工作的插件,除了最后一个(用户/地址不匹配),它可以工作:
declare @UID1 int
declare @UID2 int
declare @AID1_1 int
declare @AID1_2 int
declare @AID2_1 int
declare @AID2_2 int
insert into Users (Name)
select 'User1'
set @UID1 = SCOPE_IDENTITY()
insert into Users (Name)
select 'User2'
set @UID2 = SCOPE_IDENTITY()
insert into Addresses (UserID,Street)
select @UID1,'Street1'
set @AID1_1 = SCOPE_IDENTITY()
insert into Addresses (UserID,Street)
select @UID1,'Street2'
set @AID1_2 = SCOPE_IDENTITY()
insert into Addresses (UserID,Street)
select @UID2,'Street1'
set @AID2_1 = SCOPE_IDENTITY()
insert into Addresses (UserID,Street)
select @UID2,'Street2'
set @AID2_2 = SCOPE_IDENTITY()
insert into Orders (UserID,DeliveryAddressID,BillingAddressID)
select @UID1,@AID1_1,@AID1_2 union all
select @UID2,@AID2_1,@AID2_1
insert into Orders (UserID,DeliveryAddressID,BillingAddressID)
select @UID1,@AID1_1,@AID2_1
结果:
(1 row(s) affected)
(1 row(s) affected)
(1 row(s) affected)
(1 row(s) affected)
(1 row(s) affected)
(1 row(s) affected)
(2 row(s) affected)
Msg 547, Level 16, State 0, Line 31
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Orders_BillingAddress_UserCheck". The conflict occurred in database "Test", table "dbo.Addresses".
The statement has been terminated.
答案 1 :(得分:1)
创建一个ON INSERT触发器,以执行您要强制执行的任何其他逻辑。
缺点是用户在尝试使用错误地址时会收到错误消息...要主动,您还应该在GUI中进行此检查。
答案 2 :(得分:1)
从Order(UserID,DeliveryAddressID)到Address(UserID,ID)的复合外键是否可以执行此操作? (类似于BillingAddressID)