2011-05-26 46 views
1

我目前在SQLAzure中工作。檢查項目沒有錯誤鏈接 - 這是「外鍵約束」是什麼?

我設置了一個設計,其中每個用戶擁有一個號碼的地址的

然後,當用戶下訂單的話,我想該命令鏈接到的用戶和一對夫婦的地址。

所以我的表是這樣的:

用戶

  • 編號
  • 名稱

地址

  • 編號
  • 用戶ID(外鍵)

訂購

  • 編號
  • 用戶ID(外鍵)
  • DeliveryAddressId(外鍵)
  • BillingAddressId(外鍵)

有沒有辦法我,我可以設置SQL Server中的檢查,以便用戶可以在任何情況下(例如,通過黑客攻擊HTML POST)提交一個AddressId的訂單,該AddressId與提交的UserId沒有鏈接。我看過文檔中的「外鍵約束」,但這似乎並不是我所期望的。

任何建議什麼嘗試 - 或什麼教程閱讀 - 將不勝感激。

+0

您應該在插入之前檢查所有發送的數據。您可以在ddbb結構中設置插入時所需的字段,但您應該始終在數據服務器端檢查ddbb之前檢查它們。 – Chumillas 2011-05-26 16:01:05

+0

謝謝 - 我可以並且會這麼做 - 但是如果可以的話,我仍然希望在數據庫中設置一個檢查 - 因爲數據庫最終在參考完整性方面「最終停止」。 – Stuart 2011-05-26 16:04:07

+0

在數據庫中檢查這種情況的唯一方法是在該表中檢查完整性的ON INSERT觸發器。 [HowTo](http://msdn.microsoft.com/en-us/library/ee336242.aspx) – Chumillas 2011-05-26 16:06:01

回答

3

除了地址表(在Id上)中的主鍵,您還應該在(Id,UserId)上聲明另一個關鍵約束,UNIQUE約束。

ALTER TABLE Address ADD CONSTRAINT UQ_Address_UserCheck UNIQUE (Id,UserID) 

然後,您可以從訂單處理,或添加更多的,是檢查兩列替換現有FKS

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. 
+0

+1爲完整的工作和完整的工作示例 - 感謝巨大的努力 – Stuart 2011-05-27 17:10:22

1

創建一個ON INSERT觸發器來執行任何您想要執行的其他邏輯。

缺點是用戶在嘗試使用錯誤的地址時會收到錯誤信息...要積極主動,您還應該在GUI中執行此檢查。

+0

+1也用於GUI檢查 - 它們都是必需的,與客戶端和服務器端檢查用於Web應用程序的方式相同 - 一個是加速客戶端的反饋循環,減少開銷等,另一個是*確保*正確性。但-1訴諸觸發器。 – 2011-05-27 17:17:15

1

會從Order(UserID,DeliveryAddressID)到Address(UserID,ID)的複合外鍵做到這一點嗎? (與BillingAddressID類似)

+0

我不知何故錯過了你的答案,當我張貼我的 - 我已經擴大了這個想法。 – 2011-05-27 17:22:02