如何在SQL Server中创建真正的一对一关系
我有两个表如何在SQL Server中创建真正的一对一关系,sql,sql-server,entity-framework,one-to-one,Sql,Sql Server,Entity Framework,One To One,我有两个表Country和Capital,我将Capital的主键设置为外键,它引用Country的主键。但当我首先使用实体框架数据库时,模型是1:0..1 如何在SQL Server中创建一对一关系 我敢肯定,在SQL Server中,从技术上讲,不可能有真正的1对1关系,因为这意味着将同时在两个表中插入两条记录(否则插入时会出现约束错误),两个表之间都有外键关系 也就是说,用外键描述的数据库设计是1到0..1的关系。不存在可能需要在表B中记录的约束。您可以与在tableB中创建记录的触发器建
Country
和Capital
,我将Capital
的主键设置为外键,它引用Country
的主键。但当我首先使用实体框架数据库时,模型是1:0..1
如何在SQL Server中创建一对一关系
我敢肯定,在SQL Server中,从技术上讲,不可能有真正的1对1关系,因为这意味着将同时在两个表中插入两条记录(否则插入时会出现约束错误),两个表之间都有外键关系 也就是说,用外键描述的数据库设计是1到0..1的关系。不存在可能需要在表B中记录的约束。您可以与在tableB中创建记录的触发器建立伪关系 所以有一些伪解 首先,将所有数据存储在一个表中。那么你在EF中就没有问题了 第二,您的实体必须足够聪明,不允许插入,除非它有关联的记录 第三,也是最有可能的 更新 为了解释现实中1对1的关系是如何不起作用的,我将使用。我不打算解决这个难题,但是如果你有一个约束,说为了向鸡蛋表中添加鸡蛋,鸡的关系必须存在,并且鸡必须存在于表中,那么你不能向鸡蛋表中添加鸡蛋。反之亦然。如果蛋表中不存在与蛋和蛋的关系,则无法将鸡添加到鸡表中。因此,如果不违反其中一条规则/约束,就无法在数据库中创建任何记录
一对一关系的数据库命名法具有误导性。我所看到的所有关系(因此我的经验)都更具描述性,即一对(零或一)关系。将外键设置为主键,然后在两个主键字段上设置关系。就这样!您应该在关系线的两端看到一个关键标志。这代表着一对一
选中此项:可以通过以下方式创建简单的主外键关系并将外键列设置为唯一来完成此操作:
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]);
检查是否一切正常
SELECT * FROM [Employee];
SELECT * FROM [Salary];
现在通常处于初级对外关系(一对多),
您可以多次输入EmployeeID
,
但是这里会抛出一个错误
INSERT INTO [Salary] (
[EmployeeID]
, [SalaryAmount]
)
VALUES
(1, 3000);
上面的语句将错误显示为
违反唯一密钥约束“UQ_uuuusalary_uuu7AD04FF0C0444141D”。
无法在对象“dbo.Salary”中插入重复的密钥。重复的键值为(1)
我知道有一种方法可以实现严格的一对一关系,而无需使用触发器、计算列、附加表或其他“奇异”技巧(仅外键和唯一约束),但需要注意一点 我将借用公认答案中的鸡和蛋的概念来帮助我解释警告 事实上,无论是鸡还是蛋都必须排在第一位(无论如何,在当前的DBs中)。幸运的是,这个解决方案没有政治性,也没有规定哪一个必须放在第一位——它让实施者来决定 需要注意的是,技术上允许记录“先到”的表可以创建一个记录,而不在另一个表中创建相应的记录;然而,在这个解决方案中,只允许一个这样的记录。当只创建一条记录(仅鸡或蛋)时,在删除“lonely”记录或在另一个表中创建匹配记录之前,不能向两个表中的任何一个添加更多记录 解决方案: 向每个表添加外键,引用另一个,向每个外键添加唯一约束,并使一个外键可为null,另一个不可为null,同时也是主键。要使其工作,可为null列上的唯一约束必须只允许一个null(SQL Server中就是这种情况,其他数据库则不确定) 要插入,首先必须插入一个鸡蛋(鸡为空)。现在,只能插入一只鸡,它必须引用“无人认领”的鸡蛋。最后,添加的鸡蛋可以更新,它必须引用“无人认领”的鸡。任何时候都不能让两只鸡引用同一个鸡蛋,反之亦然 要删除,可以遵循相同的逻辑:将egg的Chicken更新为null,删除新“无人认领”的Chicken,删除egg 此解决方案还允许轻松交换。有趣的是,交换可能是使用这种解决方案最有力的理由,因为它有潜在的实际用途。通常,在大多数情况下,通过简单地将两个表重构为一个表,可以更好地实现两个表的一对一关系;然而,在一个潜在场景中,这两个表可能代表真正不同的实体,它们需要严格的一对一关系,但通常需要频繁交换“合作伙伴”或重新安排,同时在重新安排后仍保持一对一关系。如果使用更常见的解决方案,则必须更新/覆盖其中一个实体的所有数据列,以便重新排列所有对,而不是此解决方案,其中只需重新排列一列外键(可为空的外键列)
好的,这是我使用标准约束(不要判断:)所能做的最好的了,也许有人会发现它很有用。SQL中的1对1关系是通过将两个表的字段合并到一个表中来实现的 我知道可以将一个表拆分为两个具有1:1关系的实体。大多数情况下,您之所以使用它,是因为您希望在“表中的二进制数据的重字段”上使用延迟加载 示例:您有一个包含带有名称的图片的表
INSERT INTO [Salary] (
[EmployeeID]
, [SalaryAmount]
)
VALUES
(1, 3000);
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
create table dbo.[Address]
(
Id int identity not null,
City nvarchar(255) not null,
Street nvarchar(255) not null,
CONSTRAINT PK_Address PRIMARY KEY (Id)
)
create table dbo.[Person]
(
Id int identity not null,
AddressId int not null,
FirstName nvarchar(255) not null,
LastName nvarchar(255) not null,
CONSTRAINT PK_Person PRIMARY KEY (Id),
CONSTRAINT FK_Person_Address FOREIGN KEY (AddressId) REFERENCES dbo.[Address] (Id)
)
CREATE TABLE Person
(
Pk_Person_Id INT PRIMARY KEY,
Name VARCHAR(255),
EmailId VARCHAR(255),
);
CREATE TABLE PassportDetails
(
Pk_Passport_Id INT PRIMARY KEY,
Passport_Number VARCHAR(255),
Fk_Person_Id INT NOT NULL UNIQUE,
FOREIGN KEY(Fk_Person_Id) REFERENCES Person(Pk_Person_Id)
);