Добавить в корзинуПозвонить
Найти в Дзене

Уникальный индекс при мягком удалении: решаем проблему дубликатов

Пользователь обращается в поддержку: при каждом входе он видит разную историю заказов. Иногда свои, иногда чужие, иногда пустой список. Причина — три учётных записи с одним e-mail. Система аутентификации выбирает одну из них наугад, и результаты непредсказуемы. Классическое решение — уникальный индекс на столбец `email`. База данных отклоняет повторную вставку, проблема решена. Но затем появляется новое требование: пользователь должен иметь возможность удалить аккаунт и позже зарегистрироваться снова. Вы внедряете мягкое удаление — добавляете столбец `deleted_at` и помечаете запись датой удаления вместо физического стирания строки. В Laravel это делается трейтом `SoftDeletes` и вызовом `softDeletes()` в миграции. Мы уже разбирали этот механизм подробно в статье «Мягкое удаление (Soft Delete) в Laravel: полное руководство». Проблема возникает при повторной регистрации. Пользователь вводит свой старый e-mail, но уникальный индекс блокирует вставку: мягко удалённая запись всё ещё хранит э

Пользователь обращается в поддержку: при каждом входе он видит разную историю заказов. Иногда свои, иногда чужие, иногда пустой список. Причина — три учётных записи с одним e-mail. Система аутентификации выбирает одну из них наугад, и результаты непредсказуемы.

Классическое решение — уникальный индекс на столбец `email`. База данных отклоняет повторную вставку, проблема решена. Но затем появляется новое требование: пользователь должен иметь возможность удалить аккаунт и позже зарегистрироваться снова. Вы внедряете мягкое удаление — добавляете столбец `deleted_at` и помечаете запись датой удаления вместо физического стирания строки. В Laravel это делается трейтом `SoftDeletes` и вызовом `softDeletes()` в миграции. Мы уже разбирали этот механизм подробно в статье «Мягкое удаление (Soft Delete) в Laravel: полное руководство».

Проблема возникает при повторной регистрации. Пользователь вводит свой старый e-mail, но уникальный индекс блокирует вставку: мягко удалённая запись всё ещё хранит это значение. Стандартными средствами фреймворка эту коллизию не разрешить — нужно спускаться на уровень базы данных.

В этой статье мы разберём, как спроектировать ограничение уникальности, учитывающее только активные записи и игнорирующее мягко удалённые. Рассмотрим два механизма: частичные индексы в PostgreSQL и генерируемые столбцы в MySQL. Попутно затронем производительность, подводные камни восстановления записей и юридические нюансы вроде GDPR.

Материал рассчитан на тех, кто уже знаком с концепцией мягкого удаления и хочет обеспечить целостность данных на уровне схемы, а не только в коде приложения.

Читать статью полностью