【问题标题】:How to change Doctrine ORM default tracking policy to Deferred Explicit如何将 Doctrine ORM 默认跟踪策略更改为延迟显式
【发布时间】:2017-01-04 11:56:52
【问题描述】:

我正在为我的最新项目使用带有 symfony 的 Doctrine ORM。我需要我的原则默认使用延迟显式跟踪策略 - 我需要控制保存的内容和时间。

我可以在其注释中更改每个实体的学说跟踪政策

/**
* @ORM\ChangeTrackingPolicy("DEFERRED_EXPLICIT")
*/

但我想将此跟踪策略设为所有实体的默认值。我不想仅仅因为这个而创建一个共同的父实体。有没有办法为整个项目设置此跟踪策略默认值?

关于教义tracking policies

为您节省时间

【问题讨论】:

    标签: php orm doctrine-orm doctrine


    【解决方案1】:

    有一个Doctrine\ORM\Events::loadClassMetadata 事件,您可以挂钩并创建一个侦听器来覆盖实体元数据中的策略。

    在元数据从 annotations/yml/xml 加载后调用监听器,然后保存在缓存中,所以应该很有效。

    这是一些工作代码:

    class DoctrineTrackingPolicySubscriber implements EventSubscriber
    {
        public function getSubscribedEvents()
        {
            return [
                Events::loadClassMetadata
            ];
        }
    
        public function loadClassMetadata(LoadClassMetadataEventArgs $args)
        {
            $classMetadata = $args->getClassMetadata();
            $classMetadata->setChangeTrackingPolicy(
                ClassMetadataInfo::CHANGETRACKING_DEFERRED_EXPLICIT
            );
        }
    }
    

    然后在services.yamlservices.yml

    App\EventSubscriber\DoctrineTrackingPolicySubscriber:
        tags:
            - { name: doctrine.event_subscriber, connection: default }
    

    对于 Symfony 版本 class 是必要的,较新的版本隐式假定服务名称是 FQCN。

    【讨论】:

    • 这意味着您将动态更改每个类的实体跟踪策略(但不是针对每个实例)。这是可以接受的解决方案,我会给它几天,如果有人发现更明显的东西(比如教义设置)。无论如何谢谢你 - Díky Filipe :)
    • 请注意,使用 Load ClassMetadata 事件将让您覆盖任何实体的指定更改跟踪策略,但当实体未另行指定时,更改默认策略将不起作用。
    • 最好使用监听器而不是订阅者,因为订阅者必须始终被实例化,即使没有使用,而监听器仅在实际需要时才被实例化(谈到教义订阅者,symfony 订阅者的行为不同)。跨度>
    • @Rikudou_Sennin Symfony 最近引入了对惰性学说订阅者的支持
    • @FilipProcházka 在任何地方都找不到,想分享一个链接吗?
    【解决方案2】:

    您可以通过定义自己的工厂来构造 \Doctrine\ORM\Mapping\ClassMetadata,将默认的更改跟踪策略从 Deferred Implicit 更改为 Deferred Explicit

    此方法仍然允许您为您的配置指定任何一个,否则只会影响您的配置未指定的地方。

    <?php
    
    class MyClassMetadataFactory extends Doctrine\ORM\Mapping\ClassMetadataFactory
    {
        /**
         * {@inheritDoc}
         */
        protected function newClassMetadataInstance($className)
        {
            $classMetadata = parent::newClassMetadataInstance($className);
    
            // Change the default Change Tracking Policy to Deferred Explicit.
            $classMetadata->setChangeTrackingPolicy(
                Doctrine\ORM\Mapping\ClassMetadataInfo::CHANGETRACKING_DEFERRED_EXPLICIT
            );
    
            return $classMetadata;
        }
    }
    
    $xmlMetadataConfig = \Doctrine\ORM\Tools\Setup::createXMLMetadataConfiguration([__DIR__ . '/config']);
    
    // Set your class to be the factory for ClassMetadata.
    $xmlMetadataConfig->setClassMetadataFactoryName(MyClassMetadataFactory::class);
    
    $em = Doctrine\ORM\EntityManager::create(
        ['pdo' => $pdo],
        $xmlMetadataConfig
    );
    

    该策略的关键要素如下。

    • 覆盖\Doctrine\ORM\Mapping\ClassMetadataFactory::newClassMetadataInstance() 以更改\Doctrine\ORM\Mapping\ClassMetadata 的构造实例的属性。
    • 将您的类设置为要在元数据驱动程序配置中使用的工厂。

    【讨论】:

    • 这需要覆盖不打算被覆盖且对性能极其敏感的类。使用监听器可以实现同样的效果,而且更简洁,因为监听器是一个扩展点。
    • @FilipProcházka - 连接到事件侦听器并不能更改实体的 默认 策略(如果我错了,请证明。)我也是当 Doctrine 在构造实体管理器时将其作为配置选项提供时,该类不应该被覆盖的论点毫无疑问。
    • 您在技术上是正确的(在此处插入技术上正确的模因),但听众实现了相同的结果和我的主要论点 - 更干净,因为它是专用的扩展点。该类可以被覆盖,但恕我直言,应尽可能避免。
    【解决方案3】:

    我当前的解决方案只是比在项目范围内更改跟踪策略更烦人 - 我必须始终将所有更改的实体传递给 EntityManager->flush($entity=null)。换句话说 - 我必须防止在没有参数的情况下调用 flush 方法。

    【讨论】:

      猜你喜欢
      • 2012-12-13
      • 2016-10-15
      • 2010-12-02
      • 2023-04-06
      • 1970-01-01
      • 1970-01-01
      • 2019-10-15
      • 1970-01-01
      • 2021-10-19
      相关资源
      最近更新 更多