我想在SQL Server 2008 R2中創建一對一的關係。如何在SQL Server中創建真正的一對一關係
我有兩個表tableA
和tableB
,我設置tableB
的主鍵作爲外鍵,它參考tableA
的主鍵。但是當我使用實體框架數據庫時,模型是1到0..1。
任何人都知道如何在數據庫中創建真正的1對1關係?
在此先感謝!
我想在SQL Server 2008 R2中創建一對一的關係。如何在SQL Server中創建真正的一對一關係
我有兩個表tableA
和tableB
,我設置tableB
的主鍵作爲外鍵,它參考tableA
的主鍵。但是當我使用實體框架數據庫時,模型是1到0..1。
任何人都知道如何在數據庫中創建真正的1對1關係?
在此先感謝!
我敢肯定,在SQL Server中技術上不可能有一個真正的1對1關係,因爲這意味着你將有有同時插入兩個記錄(否則你會得到一個約束插入時出錯),在兩個表中,兩個表彼此具有外鍵關係。
這就是說,用外鍵描述的數據庫設計是1到0..1的關係。沒有限制可能需要tableB中的記錄。您可以與在tableB中創建記錄的觸發器建立僞關係。
所以有一些僞解決方案
首先,存儲在一個單一的表中的數據。那麼你在EF中就沒有問題了。或者其次,你的實體必須足夠聰明,除非它有相關的記錄,否則不允許插入。
UPDATE
要現實解釋如何1比1的關係不工作,我將使用Chicken or the egg dilemma的比喻。我不打算解決這個難題,但如果你有一個約束來說明爲了給雞蛋桌添加雞蛋,雞的關係必須存在,雞必須存在於桌子上,然後你不能將雞蛋添加到蛋表中。相反的情況也是如此。如果沒有與雞蛋表中存在的雞蛋和雞蛋的關係,就不能添加雞肉。因此,在不破壞任何規則/約束條件的情況下,不會在數據庫中製作任何記錄。
數據庫命名爲的一對一關係有誤導性。我所見過的所有關係(在我的經歷之前)將作爲一對一(零關係或一對)關係更具描述性。
將外鍵設置爲主鍵,然後在兩個主鍵字段上設置關係。而已!你應該在關係線的兩端看到一個關鍵標誌。這代表一對一。
檢查:SQL Server Database Design with a One To One Relationship
這將在EF中產生1到0..1的關係。 – 2012-04-24 06:05:21
@ErikPhilips我們如何通過不使用圖表編寫查詢來實現這一目標? – jason 2014-06-23 12:04:31
@jason你寫的查詢是什麼意思?你的意思是說,我如何用T-SQL中描述的關係型Pranay創建兩個表? – 2014-07-29 20:13:55
這可以通過創建一個簡單的主外鍵關係,並以下列方式中的外鍵列設置爲唯一要做:
CREATE TABLE [Employee] (
[ID] INT PRIMARY KEY
, [Name] VARCHAR(50)
);
CREATE TABLE [Salary] (
[EmployeeID] INT UNIQUE NOT NULL
, [SalaryAmount] INT
);
ALTER TABLE [Salary]
ADD CONSTRAINT FK_Salary_Employee FOREIGN KEY([EmployeeID])
REFERENCES [Employee]([ID]);
INSERT INTO [Employee] (
[ID]
, [Name]
)
VALUES
(1, 'Ram')
, (2, 'Rahim')
, (3, 'Pankaj')
, (4, 'Mohan');
INSERT INTO [Salary] (
[EmployeeID]
, [SalaryAmount]
)
VALUES
(1, 2000)
, (2, 3000)
, (3, 2500)
, (4, 3000);
看到
檢查,一切都很好現在
SELECT * FROM [Employee];
SELECT * FROM [Salary];
一般在主外的關係(一對多), 可以輸入多次EmployeeID
, 但這裏的錯誤將被拋出
INSERT INTO [Salary] (
[EmployeeID]
, [SalaryAmount]
)
VALUES
(1, 3000);
以上聲明將顯示爲錯誤
Violation of UNIQUE KEY constraint 'UQ__Salary__7AD04FF0C044141D'.
Cannot insert duplicate key in object 'dbo.Salary'. The duplicate key value is (1).
這將在實體框架中產生1到0..1的關係。您創建了一個沒有現有工資的員工。 – 2015-11-19 14:28:50
我對這最後一個例子有點好奇。如果只是將Salary對象添加到Employee類中,我將在EF中不做進一步的操作,只需在代碼中說:var salary = Employee(Id).Salary ??? – 2016-01-19 08:46:59
有一種方法我知道如何在不使用觸發器,計算列,附加表或其他「異國情調」技巧(僅限外鍵和唯一約束)的情況下實現嚴格的*一對一關係,並提供一個小警告。
我會借鑑已接受答案中的雞和雞蛋概念來幫助我解釋警告。
這是一個事實,無論是雞還是雞蛋都必須先來(無論如何都是現在的數據庫)。幸運的是,這個解決方案並不具有政治性,也沒有規定哪一個必須首先實現 - 它留給實施者。
需要注意的是,允許記錄在技術上「先到達」的表格可以在沒有相應記錄的情況下在另一個表格中創建記錄;然而,在這個解決方案中,只允許一個這樣的記錄。當僅創建一條記錄(只有雞或蛋)時,除非'寂寞'記錄被刪除或在另一個表中創建了匹配記錄,否則不能再向這兩個表中的任何一個添加記錄。
解決方案:
外鍵添加到每個表,引用其他,添加唯一約束到每個外鍵,使一個外鍵可爲空,其他不能爲空,也是一個主鍵。爲此,可空列上的唯一約束必須只允許一個空值(這是SQL Server中的情況,不確定其他數據庫)。
CREATE TABLE dbo.Egg (
ID int identity(1,1) not null,
Chicken int null,
CONSTRAINT [PK_Egg] PRIMARY KEY CLUSTERED ([ID] ASC) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE dbo.Chicken (
Egg int not null,
CONSTRAINT [PK_Chicken] PRIMARY KEY CLUSTERED ([Egg] ASC) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE dbo.Egg WITH NOCHECK ADD CONSTRAINT [FK_Egg_Chicken] FOREIGN KEY([Chicken]) REFERENCES [dbo].[Chicken] ([Egg])
GO
ALTER TABLE dbo.Chicken WITH NOCHECK ADD CONSTRAINT [FK_Chicken_Egg] FOREIGN KEY([Egg]) REFERENCES [dbo].[Egg] ([ID])
GO
ALTER TABLE dbo.Egg WITH NOCHECK ADD CONSTRAINT [UQ_Egg_Chicken] UNIQUE([Chicken])
GO
ALTER TABLE dbo.Chicken WITH NOCHECK ADD CONSTRAINT [UQ_Chicken_Egg] UNIQUE([Egg])
GO
要插入,首先必須插入一個雞蛋(對於雞爲空)。現在,只能插入一隻雞,並且必須參考「無人認領」的雞蛋。最後,添加的蛋可以更新,並且必須參考「無人認領」的雞。在任何時候,兩隻雞都不能參照相同的雞蛋,反之亦然。
要刪除,可以遵循相同的邏輯:將雞蛋的雞更新爲空,刪除新的「無人認領」雞,刪除雞蛋。
此解決方案還允許輕鬆交換。有趣的是,交換可能是使用這種解決方案的最強有力的論據,因爲它具有潛在的實際用途。通常,在大多數情況下,通過簡單地將兩個表重構爲一個,可以更好地實現兩個表的一對一關係;然而,在一個潛在的情況下,這兩個表格可能代表真正獨立的實體,這些實體需要嚴格的一對一關係,但需要經常交換「合作伙伴」或整體重新安排,同時仍保持一對一重新安排後的一對一關係。如果使用更常見的解決方案,則對於所有要重新排列的對,其中一個實體的所有數據列將不得不被更新/重寫,而與此解決方案相反,只需要重新排列一列外鍵(可以爲空的外鍵列)。
那麼,這是我能用標準約束做的最好的事情(不要判斷:)也許有人會覺得它有用。
這將在實體框架中產生1到0..1的關係。 – 2016-10-20 19:22:34
當然,在其他SQL數據庫服務器(如Oracle或PostgreSQL)中,這可以通過正確執行延遲約束來完成,這些約束在提交事務時進行檢查,而不是在插入行時進行,從而避免雞與蛋問題。令人驚訝的是,MS已經忽略了現在已有25年的SQL-92標準的這一部分。 – DaveBoltman 2017-05-08 10:26:18
在MS SQL Server中獲得真正的1:1關係的另一個更長期的方法是投票了這個連接項:https://connect.microsoft.com/SQLServer/feedback/details/124728/option-to-defer- foreign-key-constraint-checking-until-transaction-commit – DaveBoltman 2017-05-08 10:26:42
1對1 SQL中的關係通過將兩個表的字段合併爲一個!
我知道你可以用1對1關係在兩個實體中拆分表。大多數情況下,您使用這種方式是因爲您希望在「表格中重要的二進制數據字段」上使用延遲加載。
例如:您有一個包含名稱列(字符串),可能是某個元數據列,縮略圖列和圖片本身varbinary(max)的圖片的表格。在您的應用程序中,您肯定只會在收藏夾控件中首先顯示名稱和縮略圖,然後僅在需要時才加載「全部圖片數據」。
如果這是你在找什麼。這是所謂的「表分裂」或「水平分裂」。
https://visualstudiomagazine.com/articles/2014/09/01/splitting-tables.aspx
這將在實體框架中產生1到0..1的關係。 – 2017-01-20 15:47:46
實現這一點的最簡單的方法是僅創建表1與兩個表A和B字段NOT NULL。這樣就不可能有一個沒有另一個。
「......這意味着你將不得不同時插入兩個記錄」,所以一對多關係意味着你需要同時插入所有記錄? – 2012-04-24 06:28:52
不,因爲一對多實際上是1到0 ..(x)。仍然沒有要求在許多關係中有任何記錄。 :D(這是關於EF如何描述關係的具體說明,而不是我) – 2012-04-24 06:30:22
據我記得,從我的大學時代(很久很久以前),在關係數據庫中存在着一對一的關係理論。儘管如此,我仍然可能是錯的,並且在sql-server中仍然沒有明確的一對一關係。對不起,什麼是EF? – 2012-04-24 06:55:09