如何将 Doctrine ORM 默认跟踪策略更改为延迟显式
Posted
技术标签:
【中文标题】如何将 Doctrine ORM 默认跟踪策略更改为延迟显式【英文标题】:How to change Doctrine ORM default tracking policy to Deferred Explicit 【发布时间】:2017-01-04 11:56:52 【问题描述】:我正在为我的最新项目使用带有 symfony 的 Doctrine ORM。我需要我的原则默认使用延迟显式跟踪策略 - 我需要控制保存的内容和时间。
我可以在其注释中更改每个实体的学说跟踪政策
/**
* @ORM\ChangeTrackingPolicy("DEFERRED_EXPLICIT")
*/
但我想将此跟踪策略设为所有实体的默认值。我不想仅仅因为这个而创建一个共同的父实体。有没有办法为整个项目设置此跟踪策略默认值?
关于教义tracking policies。
为您节省时间
【问题讨论】:
【参考方案1】:有一个Doctrine\ORM\Events::loadClassMetadata
事件,您可以挂钩并创建一个侦听器来覆盖实体元数据中的策略。
在元数据从 annotations/yml/xml 加载后调用监听器,然后保存在缓存中,所以应该很有效。
Events: Lifecycle Events Events: Load ClassMetadata Event Symfony: How to Register Event Listeners and Subscribers这是一些工作代码:
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.yaml
或services.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 方法。
【讨论】:
以上是关于如何将 Doctrine ORM 默认跟踪策略更改为延迟显式的主要内容,如果未能解决你的问题,请参考以下文章