Какие ограничения (constraints) бывают в PostgreSQL
Что проверяют
Знаете ли вы полный набор ограничений и понимаете ли, что они защищают данные независимо от кода приложения. Для C# разработчика следом почти всегда спрашивают, как ограничения описываются в EF Core и что делать, когда база отвергла запись.
Как отвечать
Перечислите шесть видов и сразу назначение:
- NOT NULL: колонка обязана иметь значение. В EF Core его дают
IsRequired()или ненулевой тип свойства при включённых nullable reference types; - CHECK: условие на значения строки, например
CHECK (price >= 0). Ссылаться на другие таблицы не может. В EF Core задаётся черезToTable(t => t.HasCheckConstraint(...)); - UNIQUE: запрет дублей. Несколько
NULLпо умолчанию дублями не считаются, с PostgreSQL 15 это меняет опцияNULLS NOT DISTINCT. В EF Core этоHasIndex(x => x.Email).IsUnique(); - PRIMARY KEY: UNIQUE плюс NOT NULL, один на таблицу;
- FOREIGN KEY: ссылочная целостность с поведением
ON DELETE CASCADE,SET NULLилиRESTRICT. Индекс на ссылающейся колонке PostgreSQL сам не создаёт; - EXCLUDE: уникальность на произвольных операторах.
EXCLUDE USING gist (room_id WITH =, period WITH &&)запрещает пересекающиеся брони одной комнаты. Для=по целому числу в GiST нужно расширениеbtree_gist, а в EF Core такое ограничение пишут сырым SQL в миграции.
Отдельно скажите про ошибки. EF Core бросает DbUpdateException, внутри лежит PostgresException из Npgsql со свойством SqlState: 23505 для уникальности, 23503 для внешнего ключа, 23514 для CHECK. По ConstraintName можно вернуть пользователю понятное сообщение вместо 500.
Где спотыкаются
Называют DOMAIN отдельным видом ограничения. Это пользовательский тип, внутри которого живут те же CHECK и NOT NULL.
Проверяют уникальность через AnyAsync() перед вставкой. Между проверкой и записью успеет вклиниться параллельный запрос, гарантию даёт только UNIQUE в базе.
Добавляют FOREIGN KEY или CHECK на большую таблицу одной командой. Проверка всех строк идёт под блокировкой, безопаснее NOT VALID и затем VALIDATE CONSTRAINT отдельным шагом.