EntityManager使用getRepository()工厂方法的不同实例不一致)>

问题描述 投票:1回答:1

嗨,我有这个结构: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
)

我已经花了很多时间试图了解这里的情况,任何人都有建议?

  • PHP 7.2.7
  • 教义/ orm v2.6.1和v2.6.2
  • symfony / symfony v3.4.11
  • 编辑:解决了情况-错误/问题的原因

因此,我找到了一种方法,可以使用@ 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 ...

php symfony doctrine
1个回答
0
投票

TL; DR:一个错误,已在Symfony 4.3.4 / 3.4.31中修复

© www.soinside.com 2019 - 2024. All rights reserved.