【问题标题】:Foreign Key Constraints does not work with Doctrine/Symfony and SQLite外键约束不适用于 Doctrine/Symfony 和 SQLite
【发布时间】:2014-05-20 09:44:32
【问题描述】:

我正在使用 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

但是当我删除一个类别时,部门实体不会被删除,尽管约束应该级联。我错过了什么?

我是否必须进行任何配置才能使其正常工作?

【问题讨论】:

标签: php sqlite symfony doctrine-orm


【解决方案1】:

您可能需要确保在删除之前设置了PRAGMA foreign_keys = ON。

请注意,这是一个连接设置,而不是数据库设置。

补充:
使用Symfony's event subscriber,可以在执行任何写入查询之前在 Doctrine 的preFlush 事件中执行此命令。

【讨论】:

  • 请记住,即使您这样做,您仍然不能依赖 Schema Tools 来添加外键约束。它们已永久关闭
【解决方案2】:

供其他人通过 Google 来这里了解为什么在教义中不强制执行外键。

自版本 2.4.0-BETA1 起,根据 this comment 已恢复/删除了学说 dbal SqlitePlatform 中的外键支持。

这导致我在我的代码库中进行了相当多的错误搜索,只是为了发现学说本身由于不稳定而删除了该功能。

【讨论】:

    【解决方案3】:

    更改为cascade: ['persist', 'remove']

    【讨论】:

    • 是的,这是可能的,但只是一种解决方法。它不能确保数据库不会进入无效状态。
    【解决方案4】:

    pdo_sqlite 驱动程序默认禁用外键检查。正如它所提到的here:

    默认禁用外键约束(用于向后 兼容性),因此必须为每个数据库单独启用 联系。 (但是请注意,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];
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-01-14
      • 2020-03-07
      • 2014-01-17
      • 2012-02-03
      • 2013-05-03
      • 1970-01-01
      • 2011-05-14
      • 2015-09-22
      相关资源
      最近更新 更多