嗨,我有这个结构:Home N N个群组
Home.orm.yml
manyToMany: groups: targetEntity: Domain\Entity\Group inversedBy: homes joinTable: name: homes_groups joinColumns: home_id: referencedColumnName: id onDelete: CASCADE inverseJoinColumns: group_id: referencedColumnName: id onDelete: CASCADE
Home.php
protected $groups; protected $name; public function __construct($name, Group $group) { $this->name = $name; $this->groups = new ArrayCollection(); $this->addGroup($group); } public function getGroups() { return $this->groups(); } public function addGroup(Group $group) { if (!$this->getGroups()->contains($group)) { $this->getGroups()->add($group); $group->addUser($this); } }
Group.orm.yml
manyToMany: homes: targetEntity: Domain\Entity\Home orderBy: { 'name': 'ASC' } mappedBy: groups
Group.php
protected $homes; public function __construct() { $this->homes = new ArrayCollection(); } public function getHomes() { return $this->homes(); } public function addHome(Home $home) { if (!$this->getHomes()->contains($home)) { $this->getHomes()->add($home); } }
使用此Yaml将存储库作为服务注入:
repository.group: class: Infrastructure\Persistence\DoctrineORM\Repository\GroupRepository factory: ["@doctrine.orm.default_entity_manager", getRepository] arguments: - 'Domain\Entity\Group' repository.home: class: Infrastructure\Persistence\DoctrineORM\Repository\HomeRepository factory: ["@doctrine.orm.default_entity_manager", getRepository] arguments: - 'Domain\Entity\Home'
这一直有效到上周,现在当我运行此代码时,它会引发异常:
$group = $groupRepo->find(3); // Group#code = 'A' $home = new Home('test', $group); $homeRepo->getEntityManger->persist($home); $homeRepo->getEntityManger->flush();
此例外停止:
通过关系'Domain \ Entity \ Home#groups找到了一个新实体,该关系未配置为级联实体的持久操作:Domain \ Entity \ Group @ 0000000012724e2a00000000138c9399。解决t他的问题:要么在此未知实体上显式调用EntityManager#persist(),要么配置级联,以在映射中保留此关联,例如@ManyToOne(..,cascade = {“ persist”})。如果你不能找出哪个实体导致了问题,请实施“ Domain \ Entity \ Group #__ toString()”以获取线索。
很明显,如果我将
cascade: ["persist"]
放入Home#groups的yaml配置中,则会得到另一个异常:
SQL异常重复项[....] INSERT INTO组(代码)VALUES(?):['A']
使其再次起作用的唯一方法是使用GroupRepository来保留主实体:
$group = $groupRepo->find(3); $home = new Home('test', $group); $groupRepo->getEntityManger->persist($home); $groupRepo->getEntityManger->flush();
并且一切正常,创建Home并将其显示在Home表中,在连接表中创建一个新行
似乎即使使用“ @ doctrine.orm.default_entity_manager”实例化每个存储库(使用工厂方法),我对于每个存储库也具有不同的EntityManager实例。
$g = $groupRepo->find(1); $groupRepo->getEntityManager()->contains($g); // true $user = new User()... $user->addGroup($g); $userRepo->getEntityManager()->contains($user); // false $userRepo->getEntityManager()->contains($user->getGroups()->first()); // false spl_object_hash($groupRepo->getEntityManger()) // e.g. abc123 spl_object_hash($userRepo->getEntityManager()) // e.g. 456cdef
使用夹具的ObjectManager的工作
如果将上面的代码放在夹具中,而我直接使用ObjectManager,则一切正常:
class HomesFixtureLoader implements FixtureInterface, ContainerAwareInterface { // ... public function load(ObjectManager $manager) { $group = $this->container->get('groupRepo')->find(3); $home = new Home('test', $group) $manager->persist($home); $manager->flush(); } }
在灯具中,我尝试打印spl对象哈希值
public function load(ObjectManager $manager) { $groupRepo = $this->container->get('groupRepo'); $homeRepo = $this->container->get('groupRepo'); die(print_r([spl_object_hash($groupRepo->getEntityManager()), spl_object_hash($homeRepo->getEntityManager()), spl_object_hash($manager)], true)); } // RESULT Array ( [0] => 00000000024ed69f00000000656e0ce9 [1] => 00000000024ed12000000000656e0ce9 [2] => 00000000024ed69f00000000656e0ce9 )
您可以看到GroupRepository EntityManager与灯具的ObjectManager相同,而HomeRepository的EntityManager不同。这就是为什么我认为使用$ homeRepository保存$ home会出错的原因。
这仅对于GroupRepository的EntityManager成立。如果我尝试打印其他存储库的EntityManager实例的spl哈希,则将它们随机地“配对”:
public function load(ObjectManager $manager) { $groupRepo = $this->container->get('groupRepo'); $homeRepo = $this->container->get('groupRepo'); $furnitureRepo = $this->container->get('groupRepo'); $detailRepo = $this->container->get('groupRepo'); die(print_r([spl_object_hash($groupRepo->getEntityManager()), spl_object_hash($homeRepo->getEntityManager()), spl_object_hash($manager), spl_object_hash($furnitureRepo->getEntityManager(), spl_object_hash($detailRepo->getEntityManager()], true)); } // RESULT Array ( [0] => 0000000016c61829000000003b475624 // A [1] => 0000000016c61f96000000003b475624 // B [2] => 0000000016c61829000000003b475624 // A [3] => 0000000016c61f96000000003b475624 // B [4] => 0000000016c61829000000003b475624 // A )
下一个测试是尝试直接从ObjectManager获取存储库
public function load(ObjectManager $manager) { $homeRepo = $manager->getRepository('Domain:Home'); $groupRepo = $manager->getRepository('Domain:Group'); $furnitureRepo = $manager->getRepository('Domain:Furniture'); $detailRepo = $manager->getRepository('Domain:Detail'); die(print_r([spl_object_hash($groupRepo->getEntityManager()), spl_object_hash($homeRepo->getEntityManager()), spl_object_hash($manager), spl_object_hash($furnitureRepo->getEntityManager(), spl_object_hash($detailRepo->getEntityManager()], true)); } // RESULT Array ( [0] => 0000000025c5506b0000000042ab38bc [1] => 0000000025c5506b0000000042ab38bc [2] => 0000000025c5506b0000000042ab38bc [3] => 0000000025c5506b0000000042ab38bc [4] => 0000000025c5506b0000000042ab38bc )
我已经花了很多时间试图了解这里的情况,任何人都有建议?
编辑:解决了情况-错误/问题的原因
因此,我找到了一种方法,可以使用@ doctrine.orm.container_repository_factory
在我的存储库中拥有一致的EntityManager:]repository.group: class: Infrastructure\Persistence\DoctrineORM\Repository\GroupRepository factory: ["@doctrine.orm.container_repository_factory", getRepository] arguments: - '@doctrine.orm.default_entity_manager' - 'Domain\Entity\Group' repository.home: class: Infrastructure\Persistence\DoctrineORM\Repository\HomeRepository factory: ["@doctrine.orm.container_repository_factory", getRepository] arguments: - '@doctrine.orm.default_entity_manager' - 'Domain\Entity\Home' ... public function load(ObjectManager $manager) { $groupRepo = $this->container->get('groupRepo'); $homeRepo = $this->container->get('groupRepo'); $furnitureRepo = $this->container->get('groupRepo'); $detailRepo = $this->container->get('groupRepo'); print_r([ spl_object_hash($homeRepo->getEM()), spl_object_hash($groupRepo->getEM()), spl_object_hash($furnitureRepo->getEM()), spl_object_hash($detailRepo->getEM())], true)); } // RESULT Array ( [0] => 0000000066defdbc00000000687b521b [1] => 0000000066defdbc00000000687b521b [2] => 0000000066defdbc00000000687b521b [3] => 0000000066defdbc00000000687b521b )
现在
$userRepo->save($user)
运行良好。
我真的不明白为什么使用factory: ["@doctrine.orm.default_entity_manager", getRepository]
会在整个存储库中生成不一致的EntityManager实例,而使用factory: ["@doctrine.orm.container_repository_factory", getRepository]
具有更好的稳定性。真的不知道这是否是我所遇到的真正问题,因为上周一切正常,并且经过了一些顽固的重构后,此停止正常工作
嗨,我有这个结构:Home N N Groups Home.orm.yml manyToMany:groups:targetEntity:Domain \ Entity \ Group inversedBy:homes joinTable:name:homes_groups ...
TL; DR:一个错误,已在Symfony 4.3.4 / 3.4.31中修复