Как создать реальные отношения один-к-одному в SQL Server - программирование

Как создать реальные отношения один-к-одному в SQL Server

У меня есть две таблицы tableA и tableB, я устанавливаю первичный ключ tableB в качестве внешнего ключа, который ссылается на первичный ключ tableA. Но когда я использую Entity Framework для базы данных сначала, модель от 1 до 0..1.

Как создать отношение один-к-одному в SQL Server?

4b9b3361

Ответ 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)
)