php – Doctrine – Entity类中的Hydrate集合

前端之家收集整理的这篇文章主要介绍了php – Doctrine – Entity类中的Hydrate集合前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有关于双向OneToMany< - >的问题.我的实体Device和Event之间的ManyToOne关系.这是映射的外观:
// Device entity
    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Event",mappedBy="device")
     */
    protected $events;


// Event entity
    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Device",inversedBy="events")
     */
    protected $device;

问题出现是因为Device是单表继承实体

* @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="device_class_type",type="string")

每次我获取并迭代一些Event实体时,总是急切地获取$device.发生这种情况是因为它是relative documentation中报告的STI实体

There is a general performance consideration with Single Table
Inheritance: If the target-entity of a many-to-one or one-to-one
association is an STI entity,it is preferable for performance reasons
that it be a leaf entity in the inheritance hierarchy,(ie. have no
subclasses). Otherwise Doctrine CANNOT create proxy instances of this
entity and will ALWAYS load the entity eagerly.

现在有另一个名为Gateway的实体与Device和Event有关系:

/**
 * @ORM\OneToMany(targetEntity="AppBundle\Entity\Device",mappedBy="gateway")
 */
protected $devices;

/**
 * @ORM\OneToMany(targetEntity="targetEntity="AppBundle\Entity\Event",mappedBy="gateway")
 */
protected $events;


public function getEvents(): Collection
{
    return $this->events;
}

当然,每当我遍历$gateway-> getEvents()时,所有相关事件设备都会被急切地获取.即使我没有获得任何$device信息,也会发生这种情况 – 一个空的foreach就足以让Doctrine为每个对象执行1个查询获取相关的$device

foreach ($gateway->getEvents() as $event) {}

现在我知道我可以使用QueryBuilder设置一个不同的水合模式,避免$device fetching

return $this->getEntityManager()->createQueryBuilder()
            ->select('e')
            ->from('AppBundle:Event','e')
            ->where('e.gateway = :gateway')
            ->setParameter('gateway',$gateway)
            ->getQuery()->getResult(Query::HYDRATE_SIMPLEOBJECT);

但我想直接在Gateway实体中做到这一点.

那么可以直接在Gateway实体类中水合Gateway->事件吗?

你需要 write your own hydration method

您有一个循环引用,其中一个节点(Device)将强制FETCH EAGER.更糟糕的是,其中一个节点(Gateway)就像其他两个节点之间的ManyToMany连接表一样,导致FETCH EAGER在近无限循环(或至少大块相关数据)中加载所有内容.

+──<   OneToMany
 >──+   ManyToOne
 >──<   ManyToMany
 +──+   OneToOne

       ┌──────< Gateway >──────┐
       │                       │
       +                       +
     Event +──────────────< Device*

正如您所看到的,当设备执行EAGER提取时,它将收集许多网关,因此会收集许多事件,因此会有许多设备,因此会有更多网关等.获取EAGER将继续运行,直到填充所有引用.

通过建立自己的保湿器来防止“EAGER”保湿.

构建自己的保湿器需要一些仔细的数据操作,但对于您的用例可能会有些简单.记得用Doctrine注册您的保湿器,并将其作为参数传递给$query-> execute([],’GatewayHydrator’);

class GatewayHydrator extends DefaultEntityHydrator
{
    public function hydrateResultSet($stmt)
    {
        $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $class = $this->em->getClassMetadata(Gateway::class);
        $gateway = $class->newInstance();

        $gateway->setName($data[0]['gateway_name']); // example only

        return $gateway;
    }
}

或者,从设备到网关删除映射字段

删除$gateway =>来自Device的网关映射和来自Gateway->设备映射的mappedBy =“gateway”,Device将从Doctrine的角度有效地成为一片叶子.这将避免该参考循环,但有一个缺点:必须手动设置Device-> gateway属性(可能在Gateway和Event setDevice方法中).

猜你在找的PHP相关文章