如何在SQL Server中创建真正的一对一关系

时间:2012-04-24 05:46:34

标签: sql sql-server entity-framework one-to-one

我想在SQL Server 2008 R2中创建一对一的关系。

我有两个表tableAtableB,我将tableB的主键设置为外键,引用tableA的主键。但是当我首先使用Entity Framework数据库时,模型是1到0..1。

任何人都知道如何在数据库中创建真正的1对1关系吗?

8 个答案:

答案 0 :(得分:56)

将外键设置为主键,然后在两个主键字段上设置关系。而已!你应该在关系线的两端看到一个关键标志。这代表一对一。

enter image description here

请检查:SQL Server Database Design with a One To One Relationship

答案 1 :(得分:50)

我很确定在SQL Server中技术上不可能拥有真正的1对1关系,因为这意味着你同时插入两个记录(否则你' d在两个表中都有插入的约束错误,两个表之间都有外键关系。

话虽如此,使用外键描述的数据库设计是1到0..1的关系。没有约束可能需要tableB中的记录。您可以与触发器建立伪关系,以在tableB中创建记录。

所以有一些伪解决方案

首先,将所有数据存储在一个表中。那么你在EF中没有任何问题。

或者其次,您的实体必须足够聪明,不允许插入,除非它有相关记录。

或者第三,很可能是you have a problem you are trying to solve, and you are asking us why your solution doesn't work instead of the actual problem you are trying to solve (an XY Problem)

<强>更新

要在 REALITY 中解释1对1关系如何不起作用,我将使用Chicken or the egg dilemma的类比。我不打算解决这个难题,但是如果你有一个约束,为了在鸡蛋表中添加一个鸡蛋,必须存在鸡的关系,鸡必须存在于表中,然后你无法在Egg桌上添加一个Egg。反之亦然。如果没有与Egg表中存在的Egg和Egg的关系,则不能将Chicken添加到Chicken表中。因此,在不破坏其中一条规则/约束的情况下,不会在数据库中创建任何记录。

一对一关系的数据库命名法具有误导性。我所见过的所有关系(根据我的经验)将更具描述性,即一对一(零或一)关系。

答案 2 :(得分:23)

这可以通过创建简单的主外键关系并以下列方式将外键列设置为唯一来完成:

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]);

Schema

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).

答案 3 :(得分:4)

有一种方法我知道如何在不使用触发器,计算列,附加表或其他异常情况的情况下实现严格的*一对一关系。技巧(只有外键和唯一约束),有一个小警告。

我会从接受的答案中借用鸡与蛋的概念,以帮助我解释警告。

事实上,无论是鸡还是鸡蛋都必须先行(无论如何都是当前的DB)。幸运的是,这个解决方案并没有得到政治解决方案,也没有规定哪个必须首先出现 - 它将由实施者负责。

需要注意的是,该表允许记录首先出现在&#39;技术上可以创建一个没有相应记录的记录;但是,在此解决方案中,只允许一个这样的记录。当只创建一条记录(只有鸡肉或鸡蛋)时,在两个表格中的任何一个表格中都不能再添加任何记录,直到“寂寞”为止。删除记录或在另一个表中创建匹配的记录。

解决方案:

向每个表添加外键,引用另一个表,为每个外键添加唯一约束,并使一个外键可为空,另一个不可为空,也是主键。为此,可空列的唯一约束必须只允许一个空(在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

要插入,首先必须插入一个鸡蛋(鸡肉为空)。现在,只能插入一只鸡,它必须参考“无人认领的”鸡肉。蛋。最后,添加的鸡蛋可以更新,它必须参考“无人认领的”#39;鸡。在任何时候都不能让两只鸡参照同一个鸡蛋,反之亦然。

要删除,可以遵循相同的逻辑:将鸡蛋的鸡肉更新为空,删除新的&#39;无人认领的&#39;鸡肉,删掉鸡蛋。

此解决方案还允许轻松交换。有趣的是,交换可能是使用这种解决方案的最有力的论据,因为它具有潜在的实际用途。通常,在大多数情况下,通过简单地将两个表重构为一个表,可以更好地实现两个表的一对一关系;但是,在一个潜在的情况下,这两个表可能代表真正不同的实体,这需要严格的一对一关系,但需要经常交换合作伙伴&#39;或者在一般情况下重新安排,同时在重新安排后仍保持一对一的关系。如果使用更常见的解决方案,则必须针对重新排列的所有对更新/覆盖其中一个实体的所有数据列,与此解决方案相反,其中仅需要重新排列一列外键(可以为空的外键列)。​​

嗯,这是我用标准约束做的最好的事情(不要判断:)也许有人会发现它很有用。

答案 4 :(得分:1)

1到1 SQL中的关系是通过将两个表的字段合并为一个来实现的!

我知道你可以用一对一的关系将一个表拆分为两个实体。大多数时候你使用它是因为你想在“表中的二进制数据的重字段”上使用延迟加载。

例子:你有一个包含名称列(字符串)的图片的表,可能是一些元数据列,一个缩略图列和图片本身varbinary(max)。在您的应用程序中,您当然只会首先显示集合控件中的名称和缩略图,然后仅在需要时加载“完整图片数据”。

如果这是你正在寻找的。它被称为“表格分裂”或“水平分裂”。

https://visualstudiomagazine.com/articles/2014/09/01/splitting-tables.aspx

答案 5 :(得分:0)

实现此目的的最简单方法是仅创建一个表,其中表A和B字段均为NOT NULL。这样就不可能没有另一个。

答案 6 :(得分:0)

那呢?

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)
)

答案 7 :(得分:-2)

1对1的关系很有可能。即使关系图未明确显示一对一关系。如果您按以下方式实现它,它将以一对一的关系起作用。

我将使用一个基本示例来解释一个人只能拥有一本护照的概念。此示例在MS Access中运行完美。对于SQL Server版本,请遵循this link

请记住,在MS Access中,SQL脚本一次只能运行一个,而不能按此顺序显示。

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)
);