Ответ
В реляционных базах данных связи (relationships) определяют, как строки одной таблицы соотносятся со строками другой. Существует три фундаментальных типа связей, реализуемых через первичные (PK) и внешние ключи (FK).
1. Один к одному (One-to-One, 1:1)
Одна запись в таблице А связана не более чем с одной записью в таблице Б, и наоборот.
Зачем это нужно? Часто используется для разделения сущности на несколько таблиц по соображениям:
- Безопасности: Конфиденциальные данные (паспорт) отдельно от основных (пользователь).
- Производительности: Часто запрашиваемые поля — в одной таблице, редко используемые — в другой.
- Наследования (Table per Hierarchy): В ORM, например, для реализации наследования.
Реализация в БД: Внешний ключ создается в любой из таблиц, но должен быть также UNIQUE, чтобы гарантировать "один к одному".
CREATE TABLE Users (
UserId INT PRIMARY KEY,
Username NVARCHAR(50) NOT NULL
);
CREATE TABLE UserProfiles (
ProfileId INT PRIMARY KEY,
UserId INT UNIQUE NOT NULL, -- И FK, и UNIQUE!
Bio NVARCHAR(MAX),
CONSTRAINT FK_Profile_User FOREIGN KEY (UserId) REFERENCES Users(UserId)
);
2. Один ко многим (One-to-Many, 1:N)
Самая распространенная связь. Одна запись в таблице А может быть связана со многими записями в таблице Б, но запись в Б связана только с одной записью в А.
Примеры: Blog → Posts, Customer → Orders, Country → Cities.
Реализация в БД: Внешний ключ создается в таблице со стороны "многих" (таблица Б).
CREATE TABLE Blogs (
BlogId INT PRIMARY KEY,
Name NVARCHAR(100) NOT NULL
);
CREATE TABLE Posts (
PostId INT PRIMARY KEY,
Title NVARCHAR(200) NOT NULL,
BlogId INT NOT NULL, -- FK на стороне "многих"
CONSTRAINT FK_Post_Blog FOREIGN KEY (BlogId) REFERENCES Blogs(BlogId)
);
3. Многие ко многим (Many-to-Many, N:N)
Одна запись в А может быть связана со многими записями в Б, и наоборот.
Примеры: Students ↔ Courses, Products ↔ Orders, Books ↔ Authors.
Реализация в БД: Требуется промежуточная таблица-связка (junction/join table). Эта таблица содержит как минимум два внешних ключа, ссылающихся на первичные ключи связываемых таблиц. Ее составной ключ (PK1+PK2) уникален и предотвращает дублирование связей.
CREATE TABLE Students (
StudentId INT PRIMARY KEY,
Name NVARCHAR(100) NOT NULL
);
CREATE TABLE Courses (
CourseId INT PRIMARY KEY,
Title NVARCHAR(100) NOT NULL
);
-- Таблица-связка
CREATE TABLE StudentCourses (
StudentId INT NOT NULL,
CourseId INT NOT NULL,
EnrollmentDate DATE,
PRIMARY KEY (StudentId, CourseId), -- Составной первичный ключ
CONSTRAINT FK_StudentCourse_Student FOREIGN KEY (StudentId) REFERENCES Students(StudentId),
CONSTRAINT FK_StudentCourse_Course FOREIGN KEY (CourseId) REFERENCES Courses(CourseId)
);
Важно в ORM (Entity Framework Core): Для связи "многие ко многим" EF Core 5+ позволяет напрямую конфигурировать коллекции без явного создания класса для таблицы-связки, но под капотом она все равно создается.
Ответ 18+ 🔞
Давай разберём эту тему про связи в базах, а то некоторые думают, что это какая-то высшая математика, блядь. На самом деле всё просто, как три рубля, если не усложнять.
Вот смотри, есть три основных типа, как таблицы друг на друга смотрят. Всё крутится вокруг первичных и внешних ключей — это как паспорт и прописка, ёпта.
1. Один к одному (One-to-One)
Это когда одной записи в первой таблице строго соответствует не больше одной записи во второй, и наоборот. Как жена и муж в нормальной семье, блядь — у каждого должен быть только один, иначе пиздец.
Зачем это вообще нужно? Ну, например, чтобы от греха подальше. Основные данные пользователя лежат в одной таблице, а его паспортные данные, кредитная история и размер члена — в другой, защищённой. Или чтобы не тащить кучу полей, которые запрашивают раз в пятилетку. В общем, для порядка.
Как делается: Берёшь и в одну из таблиц пихаешь внешний ключ на другую, но обязательно с UNIQUE, чтобы второй раз не прицепилось. Иначе будет уже "один ко многим", а это совсем другая история.
CREATE TABLE Users (
UserId INT PRIMARY KEY,
Username NVARCHAR(50) NOT NULL
);
CREATE TABLE UserProfiles (
ProfileId INT PRIMARY KEY,
UserId INT UNIQUE NOT NULL, -- Смотри, и FK, и UNIQUE! Чтобы к одному юзеру был один профиль!
Bio NVARCHAR(MAX),
CONSTRAINT FK_Profile_User FOREIGN KEY (UserId) REFERENCES Users(UserId)
);
2. Один ко многим (One-to-Many)
Самая популярная связь, встречается на каждом шагу. Одна запись в таблице А может иметь дохуя записей в таблице Б, но каждая запись из Б привязана только к одной из А. Как начальник и его отдел: у начальника много подчинённых, а у каждого подчинённого — один начальник (если, конечно, он не работает на двух хозяев, пидор).
Примеры: Блог и посты, заказчик и его заказы, страна и города.
Как делается: Внешний ключ ставится в таблицу "многих". Всё логично — подчинённый хранит id своего начальника.
CREATE TABLE Blogs (
BlogId INT PRIMARY KEY,
Name NVARCHAR(100) NOT NULL
);
CREATE TABLE Posts (
PostId INT PRIMARY KEY,
Title NVARCHAR(200) NOT NULL,
BlogId INT NOT NULL, -- Вот он, FK! Пост знает, к какому блогу приписан.
CONSTRAINT FK_Post_Blog FOREIGN KEY (BlogId) REFERENCES Blogs(BlogId)
);
3. Многие ко многим (Many-to-Many)
А вот это уже веселее. Одна запись в А может ссылаться на много записей в Б, и наоборот. Как студенты и курсы: один студент ходит на много курсов, а на один курс записывается много студентов. Или продукты в заказе — полная жопа, если делать напрямую.
Как делается: Тут без промежуточной таблицы-связки — никак, блядь. Она как сводница между двумя другими. В этой таблице-связке сидят минимум два внешних ключа, которые тыкают в исходные таблицы. А её составной первичный ключ (оба FK вместе) не даёт создать одну и ту же связь дважды.
CREATE TABLE Students (
StudentId INT PRIMARY KEY,
Name NVARCHAR(100) NOT NULL
);
CREATE TABLE Courses (
CourseId INT PRIMARY KEY,
Title NVARCHAR(100) NOT NULL
);
-- А вот и наша сводница
CREATE TABLE StudentCourses (
StudentId INT NOT NULL,
CourseId INT NOT NULL,
EnrollmentDate DATE,
PRIMARY KEY (StudentId, CourseId), -- Составной ключ. Не даст одному студенту дважды на один курс записаться.
CONSTRAINT FK_StudentCourse_Student FOREIGN KEY (StudentId) REFERENCES Students(StudentId),
CONSTRAINT FK_StudentCourse_Course FOREIGN KEY (CourseId) REFERENCES Courses(CourseId)
);
Важный момент для тех, кто пишет на EF Core: Начиная с пятой версии, можно в коде делать вид, что этой таблицы-связки нет, просто объявить коллекции друг у друга. Но не обманывайся — под капотом эта самая сводница всё равно создастся, её не обойти. ORM — он хоть и умный, но не волшебник, ёпта.