steevanb / doctrine-entity-merger
添加提示 MERGE_ENTITY 以合并由多次查询检索的字段
1.0.5
2018-05-24 10:15 UTC
Requires
- php: ^5.4.0 || ^7.0
- doctrine/orm: ^2.4.8
- steevanb/doctrine-events: ^1.0
README
doctrine-entity-merger
当你在DQL中使用PARTIAL时,你只会检索需要的字段,而不是所有实体字段。
但是,如果你在同一个实体上执行了2次PARTIAL,但字段不同,你将遇到这个问题
class FooEntity { protected $id; protected $name; protected $description; } $foo1 = $repository ->createQueryBuilder('foo') ->select('PARTIAL foo.{id, name}') ->where('site.id = 1') ->getQuery() ->getSingleResult(); var_dump($foo1->getDescription()); // null, that's fine, description is not in PARTIAL $foo2 = $repository ->createQueryBuilder('foo') ->select('PARTIAL foo.{id, name, description}') ->where('site.id = 1') ->getQuery() ->getSingleResult(); // $foo1 is same object as $foo2, cause Doctrine know first query hydrated $foo1 // so, when you ask same entity (same id in query) with 2nd query, Doctrine will execute SQL, // but will not hydrate a new entity // UnitOfWork will return instance of Foo who is already hydrated, with first query var_dump(spl_object_hash($foo1) === spl_object_hash($foo2)); // true // but, as Doctrine return $foo1 in 2nd query, your new field description will not be defined in $foo1 var_dump($foo1->getDescription()); // null, but we want it, cause it's defined in PARTIAL 2nd query
你可以使用 steevanb\DoctrineEntityMerger\QueryHint::MERGE_ENTITY 来定义 $foo1 中的描述
use steevanb\DoctrineEntityMerger\QueryHint; $foo1 = $repository ->createQueryBuilder('foo') ->select('PARTIAL foo.{id, name}') ->where('site.id = 1') ->getQuery() ->getSingleResult(); var_dump($foo1->getName()); // 'My name' for example var_dump($foo1->getDescription()); // null, that's fine, description is not in PARTIAL $foo1->setName('New name'); var_dump($foo1->getName()); // 'New name' $foo2 = $repository ->createQueryBuilder('foo') ->select('PARTIAL foo.{id, description}') ->where('site.id = 1') ->getQuery() ->setHint(QueryHint::MERGE_ENTITY, true) ->getSingleResult(); var_dump($foo1->getName()); // 'New name', MERGE_ENTITY will not change Foo::$name value if it was already defined in another query before var_dump($foo1->getDescription()); // 'My description'
安装
由于 doctrine-entity-merger 使用 steevanb/doctrine-events,请查看如何安装它(在此处添加了composer依赖项,你不需要为steevanb/doctrine-events添加它)
将其添加到你的composer.json中
{ "require": { "steevanb/doctrine-entity-merger": "^1.0.5", } }
添加EntityMergerSubscriber
$entityManager->getEventManager()->addEventSubscriber( new steevanb\DoctrineEntityMerger\EventSubscriber\EntityMergerSubscriber() );
如果你想将MERGE_ENTITY提示添加到所有查询中,你可以这样做
$entityManager->getConfiguration()->setDefaultQueryHint( steevanb\DoctrineEntityMerger\QueryHint\QueryHint::MERGE_ENTITY, true );
例如,如果你在一个Symfony项目中,你可以在AppKernel中添加它
# app/AppKernel.php use Doctrine\ORM\EntityManagerInterface; use steevanb\DoctrineEntityMerger\QueryHint; use steevanb\DoctrineEntityMerger\EventSubscriber\EntityMergerSubscriber; class AppKernel { public function boot() { parent::boot(); foreach ($this->getContainer()->get('doctrine')->getManagers() as $manager) { if ($manager instanceof EntityManagerInterface) { // add hint MERGE_ENTITY to all your queries $manager->getConfiguration()->setDefaultQueryHint(QueryHint::MERGE_ENTITY, true); // add listener, who use steevanb/doctrine-events to change UnitOfWork::createEntity() // to take into account MERGE_ENTITY hint $manager->getEventManager()->addEventSubscriber(new EntityMergerSubscriber()); } } } }