2015-03-19 68 views
1

我有這樣一個場景:MSSQL約束可能會導致循環或多個級聯路徑

User可以擁有多個AccountsUser也有比特幣地址(他自己輸入),他們是「取款地址」。每個Account也可能有多個比特幣地址(這是「存款地址」)。

所有的地址都在一張表中,唯一的區別是存款/提款只是在表BitcoinAddresses的列Type中指定。

我想創建一個場景,其中刪除User將導致他擁有的所有提款BitcoinAddresses被刪除,並且他所擁有的所有Accounts都將被刪除。但刪除Account應該會導致BitcoinAddresses引用設置爲NULL

我已經試過類似的東西:

CREATE TABLE [dbo].[Users] (
    [Id]     NVARCHAR (128) NOT NULL, 
    [UserName]   NVARCHAR (64) NULL, 
    CONSTRAINT [PK_dbo.Users] PRIMARY KEY CLUSTERED ([Id] ASC), 
); 

CREATE TABLE [dbo].[Accounts] (
    [Id]  BIGINT   IDENTITY (1, 1) NOT NULL, 
    [UserId] NVARCHAR (128) NOT NULL, 
    [Number] BIGINT   NOT NULL, 
    CONSTRAINT [PK_dbo.Accounts] PRIMARY KEY CLUSTERED ([Id] ASC), 
    CONSTRAINT [FK_dbo.Accounts.Users_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[Users] ([Id]) ON DELETE CASCADE 
); 

CREATE TABLE [dbo].[BitcoinAddresses] (
    [BitcoinAddressId] INT   IDENTITY (1, 1) NOT NULL, 
    [Address]   NVARCHAR (MAX) NOT NULL, 
    [AccountId]  BIGINT   NULL, 
    [UserId]   NVARCHAR (128) NULL, 
    [Type]   NVARCHAR (MAX) NULL, 
    CONSTRAINT [PK_dbo.BitcoinAddresses] PRIMARY KEY CLUSTERED ([BitcoinAddressId] ASC), 
    CONSTRAINT [FK_dbo.BitcoinAddresses_dbo.Accounts_AccountId] FOREIGN KEY ([AccountId]) REFERENCES [dbo].[Accounts] ([Id]) ON DELETE SET NULL, 
    CONSTRAINT [FK_dbo.BitcoinAddresses_dbo.Users_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[Users] ([Id]) ON DELETE CASCADE 
); 

該解決方案將導致錯誤:

Introducing FOREIGN KEY constraint 'FK_dbo.BitcoinAddresses_dbo.Users_UserId' on table 'BitcoinAddresses' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. 

但很明顯,我不認爲在這種方法中的任何週期。你能向我解釋爲什麼會發生這種行爲嗎?我該如何解決它?我想說明的是,我不想將Wihtdrawal和存款地址分爲兩個不同的表格(因爲這將是此場景的正確解決方案,但我想知道爲什麼我無法創建此類參考)

這裏是我的小提琴玩:http://sqlfiddle.com/#!6/5d9cd

+0

您的設計還有一個問題。 'BitcoinAddresses'中的一行可以使用不同的'UserId'來引用'User'和'Account'。這是故意的嗎?如果沒有,你可以刪除2個FK,只用一個:'FOREIGN KEY(UserId,AccountId)REFERENCES [dbo]。[Accounts](UserId,Id)',你將能夠解決你的問題;)哦,你需要在'Accounts'中添加一個'UNIQUE'約束來定義上面的FK。 – 2015-03-19 14:05:42

+0

將表分成兩個似乎是最好的解決方案。人們只需要FK給用戶(並且沒有AccountID列),另一個只需要帳戶。沒有多個級聯路徑和不可空列。 – 2015-03-19 14:18:40

+0

感謝您的建議。我知道我可以將它分成兩個表格,但在我的情況下並不那麼容易,因爲整個場景都是由Entity Framework管理的。所以這個框架確保我沒有在一個'BitcoinAddress'上有不同'Account'和'User'的情況。不過謝謝你的注意,很好! – 2015-03-19 14:50:29

回答

3

如果你刪除一個用戶,他的帳戶將被刪除,他的bitcoinaddresses將被刪除。但是,當他的account被刪除時,賬戶的bitcoinaddresses也將更新爲NULL。這對於SQL Server來說太複雜了。它需要級聯鏈是簡單和整潔的,而不是分支和/或收斂。如果用戶刪除會導致刪除比特幣並將其帳戶設置爲NULL,那麼SQL Server如何知道您想要的?

+1

你是對的,但即使我已經將它設置爲CASCADE刪除每個參考,然後它會給我同樣的錯誤。 – 2015-03-19 13:48:05

+0

是的,出於同樣的原因。兩個級聯路徑會聚。這是根本原因。 SQL沒有編程思考如果收斂級聯實際上會導致問題。如果它看到潛在的收斂,就會產生一個錯誤。 – 2015-03-19 13:50:07

+0

@TabAlleman請編輯您的naswer,從「SQL」到「SQL-Server」。還有其他SQL產品(如Postgres)可以很好地處理多個級聯路徑。SQL-Server架構師選擇禁止這樣做(出於某些原因,不存在爭論)。 – 2015-03-19 14:01:35

相關問題