В этой статье мы разберем, как создавать уникальные индексы в Doctrine (для Symfony) и MySQL. Вы узнаете:
- Как определять уникальные поля через Doctrine ORM
- Особенности работы UNIQUE-индексов с NULL-значениями
- Как создавать составные уникальные индексы
- Различия между MySQL и другими СУБД
1. Создание уникальных индексов в Doctrine
1.1. Через атрибуты (PHP 8+)
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
#[ORM\Table(name: 'users')]
#[ORM\UniqueConstraint(name: 'unique_email', columns: ['email'])]
class User
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(type: 'string', length: 255, unique: true)]
private string $email;
}
1.2. Через YAML-конфигурацию
App\Entity\User:
type: entity
table: users
uniqueConstraints:
unique_email:
columns: [email]
fields:
email:
type: string
unique: true
1.3. Составные уникальные индексы
#[ORM\Entity]
#[ORM\Table(uniqueConstraints: [
new ORM\UniqueConstraint(
name: 'unique_user_product',
columns: ['user_id', 'product_id']
)
])]
class CartItem
{
#[ORM\ManyToOne(targetEntity: User::class)]
private User $user;
#[ORM\ManyToOne(targetEntity: Product::class)]
private Product $product;
}
2. Особенности работы с NULL в MySQL
2.1. Поведение NULL в UNIQUE-индексах
CREATE TABLE users (
email VARCHAR(255) UNIQUE
);
INSERT INTO users (email) VALUES (NULL), (NULL); -- Разрешено в MySQL
2.2. Как запретить дубликаты NULL
Вариант 1: Использовать NOT NULL
CREATE TABLE users (
email VARCHAR(255) NOT NULL DEFAULT '',
UNIQUE (email)
);
Вариант 2: Триггер для проверки
DELIMITER //
CREATE TRIGGER prevent_null_duplicates
BEFORE INSERT ON users
FOR EACH ROW
BEGIN
IF NEW.email IS NULL AND EXISTS (
SELECT 1 FROM users WHERE email IS NULL
) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Duplicate NULL values not allowed';
END IF;
END//
DELIMITER ;
Минус триггера, дополнительная нагрузка на БД и время выполнения запроса.
3. Различия между СУБД
СУБД | Поведение NULL в UNIQUE |
---|---|
MySQL | Разрешает несколько NULL |
PostgreSQL | Разрешает только один NULL |
4. Проверка индексов
В Doctrine:
php bin/console doctrine:schema:validate
В MySQL:
SHOW INDEX FROM users WHERE Non_unique = 0;
Заключение
- Используйте
unique: true
илиUniqueConstraint
в Doctrine - Помните о различиях в обработке NULL разными СУБД
- Для строгой уникальности заменяйте NULL на пустые строки
- Составные индексы работают по-разному в MySQL 8.0+
Совет: Всегда проверяйте поведение UNIQUE-индексов в вашей версии СУБД перед развертыванием в production.
Добавить комментарий