Как создать реальные отношения один-к-одному в SQL Server
У меня есть две таблицы tableA
и tableB
, я устанавливаю первичный ключ tableB
в качестве внешнего ключа, который ссылается на первичный ключ tableA
. Но когда я использую Entity Framework для базы данных сначала, модель от 1 до 0..1.
Как создать отношение один-к-одному в SQL Server?
Ответы
Ответ 1
Я почти уверен, что в SQL Server технически невозможно иметь отношение True 1 к 1, поскольку это означает, что вам придется вставлять обе записи одновременно (в противном случае вы получите ошибку ограничения при вставке), в обе таблицы, причем обе таблицы имеют отношение внешнего ключа друг к другу.
Тем не менее, ваша структура базы данных, описанная с помощью внешнего ключа, представляет собой отношение от 1 до 0..1. Нет никаких ограничений, которые потребовали бы записи в таблице B. Вы можете иметь псевдосвязь с триггером, который создает запись в таблице B.
Так что есть несколько псевдо-решений
Во-первых, сохраните все данные в одной таблице. Тогда у вас не будет проблем в EF.
Или, во-вторых, ваша сущность должна быть достаточно умной, чтобы не допустить вставки, если у нее нет связанной записи.
Или, в-третьих, и, скорее всего, у вас есть проблема, которую вы пытаетесь решить, и вы спрашиваете нас, почему ваше решение не работает вместо реальной проблемы, которую вы пытаетесь решить (проблема XY).
ОБНОВИТЬ
Чтобы объяснить в РЕАЛЬНОСТИ, как отношения 1 к 1 не работают, я буду использовать аналогию с Цыпленком или дилеммой яйца. Я не собираюсь решать эту дилемму, но если у вас должно быть ограничение, которое говорит, что для добавления яйца в таблицу яиц, отношения курицы должны существовать, а курица должна существовать в таблице, тогда Вы не можете добавить яйцо в таблицу яиц. Обратное тоже верно. Вы не можете добавить Цыпленок в таблицу Цыпленок без связи с Яйцом и Яйцом, существующими в таблице Яйца. Таким образом, никакие записи не могут быть сделаны в базе данных без нарушения одного из правил/ограничений.
Номенклатура базы данных отношения один к одному вводит в заблуждение. Все отношения, которые я видел (прежде всего мой опыт), были бы более описательными как отношения один к (ноль или один).
Ответ 2
Установите внешний ключ в качестве первичного ключа, а затем установите связь в обоих полях первичного ключа. Это! Вы должны увидеть знак ключа на обоих концах линии отношений. Это представляет собой один к одному.
![enter image description here]()
Проверьте это: Конструкция базы данных SQL Server с отношением "один к одному"
Ответ 3
Это можно сделать, создав простое отношение первичного внешнего ключа и установив уникальный для столбца внешнего ключа следующим образом:
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);
В приведенном выше утверждении ошибка будет отображаться как
Нарушение ограничения UNIQUE KEY 'UQ__Salary__7AD04FF0C044141D'. Невозможно вставить дубликат ключа в объект 'dbo.Salary'. Значение дубликата ключа (1).
Ответ 4
Есть один способ, которым я знаю, как добиться строго "одного к одному" отношения без использования триггеров, вычисленных столбцов, дополнительных таблиц или других "экзотических" трюков (только внешние ключи и уникальные ограничения) с одним небольшим предостережением.
Я возьму концепцию цыпленка и яйца из принятого ответа, чтобы помочь мне объяснить оговорку.
Это факт, что либо курица, либо яйцо должны на первом месте (в текущих БД). К счастью, это решение не становится политическим и не предписывает, что должно быть первым - оно оставляет его исполнителю.
Предостережение состоит в том, что таблица, которая позволяет записи "прийти первым" технически, может иметь запись, созданную без соответствующей записи в другой таблице; однако в этом решении допускается только одна такая запись. Когда создается только одна запись (только цыпленок или яйцо), никакие записи не могут быть добавлены ни к одной из двух таблиц, пока не будет удалена либо "одиночная" запись, либо соответствующая запись будет создана в другой таблице.
Решение:
Добавьте внешние ключи в каждую таблицу, ссылаясь на другую, добавьте уникальные ограничения для каждого внешнего ключа и сделайте один внешний ключ с нулевым значением, а другой - недействительным, а также первичный ключ. Чтобы это сработало, уникальный ограничитель в столбце с нулевым значением должен допускать только один null (это имеет место в 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
Чтобы вставить, сначала необходимо добавить яйцо (с нулевым значением для цыпленка). Теперь можно добавить только курицу, и она должна ссылаться на "невостребованное" яйцо. Наконец, добавленное яйцо можно обновить, и оно должно ссылаться на "невостребованную" курицу. Ни в коем случае нельзя назначать двух цыплят, чтобы ссылаться на одно и то же яйцо или наоборот.
Чтобы удалить, можно следовать той же логике: обновить яйцо Курица до нуля, удалить недавно "невостребованную" курицу, удалить яйцо.
Это решение также позволяет легко переключаться. Интересно, что обмен может быть самым сильным аргументом в пользу использования такого решения, поскольку он имеет потенциальное практическое применение. Обычно в большинстве случаев взаимно-однозначное соотношение двух таблиц лучше реализуется путем простого преобразования двух таблиц в один; однако в потенциальном сценарии две таблицы могут представлять собой по-настоящему разные сущности, которые требуют строгой взаимно-однозначной взаимосвязи, но им необходимо часто менять "партнеров" или перестраиваться в целом, сохраняя при этом одностороннее -отношения после переустановки. Если использовалось более распространенное решение, все столбцы данных одного из объектов должны были быть обновлены/перезаписаны для всех перестраиваемых пар, в отличие от этого решения, где нужно переустановить только один столбец внешних ключей (столбец с нулевым внешним ключом).
Хорошо, это лучшее, что я мог сделать, используя стандартные ограничения (не судите:) Может быть, кто-то найдет это полезным.
Ответ 5
1 To 1 Отношения в SQL производятся путем слияния поля обеих таблиц в одном!
Я знаю, что вы можете разбить таблицу на два объекта с отношением 1 к 1. В большинстве случаев вы используете это, потому что хотите использовать ленивую загрузку на "тяжелом поле двоичных данных в таблице".
Пример: у вас есть таблица, содержащая изображения с колонкой имен (строка), возможно, столбец метаданных, столбец эскизов и сама картина varbinary (max). В вашем приложении вы обязательно будете отображать сначала только имя и миниатюру в элементе управления коллекцией, а затем загружать "полные данные изображения" только при необходимости.
Если это то, что вы ищете. Это то, что называется "разделение таблицы" или "горизонтальное расщепление".
https://visualstudiomagazine.com/articles/2014/09/01/splitting-tables.aspx
Ответ 6
Самый простой способ добиться этого - создать только 1 таблицу с полями Table A и B NOT NULL. Таким образом, невозможно иметь одно без другого.
Ответ 7
Как насчет этого?
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)
)