gpt4 book ai didi

php - 学说 - 实体类中的水合物收集

转载 作者:可可西里 更新时间:2023-11-01 12:58:24 29 4
gpt4 key购买 nike

我有关于双向 OneToMany <-> ManyToOne 的问题我的实体之间的关系 DeviceEvent .这是映射的样子:

// 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总是热切地被获取。发生这种情况是因为它是一个 STI 实体,如 related documentation 中所报告的那样

There is a general performance consideration with Single TableInheritance: If the target-entity of a many-to-one or one-to-oneassociation is an STI entity, it is preferable for performance reasonsthat it be a leaf entity in the inheritance hierarchy, (ie. have nosubclasses). Otherwise Doctrine CANNOT create proxy instances of thisentity 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获取

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

但我想以某种方式直接在 Gateway 中进行实体。

那么有没有可能水合物Gateway->events直接在Gateway实体类?

最佳答案

你需要write your own hydration method

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

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

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

如您所见,当设备执行 EAGER 获取时,它将收集许多 Gateways,因此收集许多 Events,因此收集许多 Devices,因此还有更多的网关等。Fetch EAGER 将继续运行,直到所有引用都被填充。

通过构建您自己的 Hydrator 来防止“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;
}
}

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

Device 中删除 $gateway => Gateway 映射,从 Gateway->device 中删除 mappedBy="gateway" 映射,从 Doctrine 的角度来看,Device 将有效地成为一片叶子。这将避免引用循环,但有一个缺点:必须手动设置 Device->gateway 属性(可能在 Gateway 和 Event setDevice 方法中)。

关于php - 学说 - 实体类中的水合物收集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48211155/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com