我正在使用 Doctrine 2.4.2、Symfony 2.4 和 SQLite 3.8.3。
我定义了两个实体:
Category:
type: entity
id:
id:
type: integer
id: true
generator:
strategy: AUTO
oneToMany:
ministries:
targetEntity: Ministry
cascade: [persist]
mappedBy: category
还有
Ministry:
type: entity
id:
id:
type: integer
id: true
generator:
strategy: AUTO
manyToOne:
category:
targetEntity: Category
inversedBy: ministries
joinColumn:
name: category_id
nullable: false
onDelete: CASCADE
但是当我删除一个类别时,尽管约束应该级联,但部门实体不会被删除。我错过了什么?
我需要配置任何东西才能使其正常工作吗?
您可能需要确保在删除之前设置
PRAGMA foreign_keys = ON
。
请注意,这是连接设置,而不是数据库设置。
补充:
使用 Symfony 的事件订阅者,可以在执行任何写入查询之前在 Doctrine 的 preFlush 事件中执行此命令。
对于通过 Google 来到这里了解为什么外键在原则中不强制执行的其他人。
自版本 2.4.0-BETA1 以来,dbal SqlitePlatform 中的外键支持已根据此评论恢复/删除。
这导致我在代码库中进行了相当多的错误搜索,只是为了发现该学说本身由于不稳定而删除了该功能。
更改为
cascade: ['persist', 'remove']
pdo_sqlite 驱动程序默认禁用外键检查。正如这里提到的:
默认情况下禁用外键约束(对于向后 兼容性),因此必须为每个数据库单独启用 联系。 (但是请注意,SQLite 的未来版本可能会 更改以便默认启用外键约束。小心 开发商不会对是否为外资做出任何假设 默认情况下启用键,但会启用或禁用它们 必要的。
您应该在通过 EeventSubscriber 刷新之前启用它:
<?php declare(strict_types=1);
namespace App\EventSubscriber;
use Doctrine\Bundle\DoctrineBundle\EventSubscriber\EventSubscriberInterface;
use Doctrine\ORM\Event\PreFlushEventArgs;
use Doctrine\ORM\Events;
/**
* Class SqlitePreFlushSubscriber.
*/
final class SqlitePreFlushSubscriber implements EventSubscriberInterface
{
public function preFlush(PreFlushEventArgs $args): void
{
if ('sqlite' !== \strtolower($args->getEntityManager()->getConnection()->getDatabasePlatform()->getName())) {
return;
}
$args->getEntityManager()->getConnection()->exec('PRAGMA foreign_keys = ON;');
}
/**
* @return string[]
*/
public function getSubscribedEvents(): array
{
return [Events::preFlush];
}
}
如果你想在 Symfony 6.3 中始终启用 sqlite 的外键约束,你可以创建以下事件监听器:)
<?php
# src/EventListener/SqlitePreFlush.php
namespace App\EventListener;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\ORM\Event\PreFlushEventArgs;
use Doctrine\ORM\Events;
#[AsDoctrineListener(event: Events::preFlush, priority: 500, connection: 'default')]
class SqlitePreFlush
{
/**
* @throws Exception
*/
public function preFlush(PreFlushEventArgs $args): void
{
$connection = $args->getObjectManager()->getConnection();
if ($connection->getDatabasePlatform() instanceof SqlitePlatform) {
$connection->executeStatement('PRAGMA foreign_keys = ON;');
}
}
}