【问题标题】:Symfony 4 : Doctrine2 LAZY Fetch Collection still empty after calling the getterSymfony 4:调用 getter 后,Doctrine2 LAZY Fetch Collection 仍然为空
【发布时间】:2020-06-04 15:20:47
【问题描述】:

我对某些实体有疑问:根据the doctrine documentation,延迟加载应该只允许我在调用 getter 时加载我的集合,但它没有。

这是关系描述:

一个位置有许多场地,由位置“externalId”字段映射。

这是我的实体及其关系的简化代码示例:

// Location.php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity(repositoryClass="App\Repository\LocationRepository")
 * @ORM\Table(name="Location")
 */
class Location extends Entity
{
    /**
     * @var integer
     * @ORM\Column(type="integer", unique=true, nullable=true)
     */
    protected $locationId;

    /**
     * @var integer
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer", nullable=false)
     */
    protected $externalId;

    /**
     * @var Venue[]|Collection
     * @ORM\OneToMany(targetEntity="App\Entity\Venue", mappedBy="locationExternalId", orphanRemoval=true, fetch="LAZY")
     */
    protected $venues;

    /**
     * Location constructor.
     * @param array $data
     */
    public function __construct(array $data)
    {
        $this->venues = new ArrayCollection;
        $this->hydrate($data);
    }

    /**
     * @return int
     */
    public function getLocationId()
    {
        return $this->locationId;
    }

    /**
     * @param int $locationId
     * @return $this
     */
    public function setLocationId($locationId)
    {
        $this->locationId = $locationId;
        return $this;
    }

    /**
     * @return Venue[]|Collection
     */
    public function getVenues()
    {
        return $this->venues;
    }

    /**
     * @param Venue[]|Collection $venues
     * @return $this
     */
    public function setVenues($venues)
    {
        $this->venues = $venues;
        return $this;
    }
}

// Venue.php
namespace App\Entity;

use App\Entity\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity(repositoryClass="App\Repository\VenueRepository")
 * @ORM\Table(name="Venue", indexes={@ORM\Index(name="IDX_Venue", columns={"location_id"})})
 */
class Venue extends Entity
{
    /**
     * @var integer
     * @ORM\Column(type="integer", unique=true, nullable=true)
     */
    protected $venueId;

    /**
     * @var integer
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer", nullable=false)
     */
    protected $externalId;

    /**
     * @var Location
     * @ORM\ManyToOne(targetEntity="App\Entity\Location", inversedBy="venues")
     * @ORM\JoinColumn(name="location_external_id", referencedColumnName="external_id", nullable=true)
     */
    protected $locationExternalId;

    /**
     * Venue constructor.
     * @param array $data
     */
    public function __construct(array $data)
    {
        $this->hydrate($data);
    }

    /**
     * @return int
     */
    public function getVenueId()
    {
        return $this->venueId;
    }

    /**
     * @param int $venueId
     * @return $this
     */
    public function setVenueId($venueId)
    {
        $this->venueId = $venueId;
        return $this;
    }

    /**
     * @return int
     */
    public function getExternalId()
    {
        return $this->externalId;
    }

    /**
     * @param int $externalId
     * @return $this
     */
    public function setExternalId($externalId)
    {
        $this->externalId = (int)$externalId;
        return $this;
    }

    /**
     * @return Location
     */
    public function getLocationExternalId()
    {
        return $this->locationExternalId;
    }

    /**
     * @param Location $locationExternalId
     * @return $this
     */
    public function setLocationExternalId($locationExternalId)
    {
        $this->locationExternalId = $locationExternalId;
        return $this;
    }
}

如果我加载一个位置,场地没有初始化,这是预期的:

// Controller.php
use App\Entity\Basketball\Location;
use App\Entity\Basketball\Venue;

$location = $this->getDoctrine()->getRepository(Location::class)->findOneBy(['externalId' => 1]);
dump($location);

// Dump results
App\Entity\Location {#1438 ▼   #locationId: 1644  
#externalId: 1
#venues: Doctrine\ORM\PersistentCollection {#1450 ▼
    -snapshot: []
    -owner: App\Entity\Location {#1438}
    -association: array:15 [ …15]
    -em: Doctrine\ORM\EntityManager {#75 …11}
    -backRefFieldName: "locationExternalId"
    -typeClass: Doctrine\ORM\Mapping\ClassMetadata {#1441 …}
    -isDirty: false
    #collection: Doctrine\Common\Collections\ArrayCollection {#1700 ▶}
    #initialized: false

但它应该通过调用 getter,它没有按预期工作

// Controller.php
dump($location->getVenues());

// Dump results
Doctrine\ORM\PersistentCollection {#1450 ▼
  -snapshot: []
  -owner: App\Entity\Location {#1438 ▶}
  -association: array:15 [ …15]
  -em: Doctrine\ORM\EntityManager {#75 …11}
  -backRefFieldName: "locationExternalId"
  -typeClass: Doctrine\ORM\Mapping\ClassMetadata {#1441 …}
  -isDirty: false
  #collection: Doctrine\Common\Collections\ArrayCollection {#1700 ▼
    -elements: []
  }
  #initialized: false
}

环境

  • Symfony v4.4.7
  • Doctrine v2.7 ("doctrine/doctrine-fixtures-bundle": "^3.3")
  • 通过指定“fetch=EAGER”,它可以工作,但我不想...

有什么想法吗?我应该怎么做才能初始化我的收藏?

编辑

感谢this Github issue 我找到了一种解决方法,方法是在 getter 中初始化集合,但仍然如此;应该有一种方法可以自动完成:

public function getVenues()
{
    $this->venues->initialize();
    return $this->venues;
}

【问题讨论】:

    标签: orm doctrine symfony4


    【解决方案1】:

    真的需要你吗?要初始化集合,您需要调用此集合的某些方法。如果您使用JMSSerializerSymfony Serializer,您可以只返回序列化的数据,序列化程序会为您完成所有工作,因为它们调用toArray 方法来初始化您的集合。

    【讨论】:

    • 嗯,非常感谢,你是对的。文档不清楚,但“首次访问”意味着调用集合的方法。我不使用 JMSSerializer 或 Symfony Serializer,但我可以手动调用 toArray 方法,它工作正常:$location->getVenues()->toArray();
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-16
    • 1970-01-01
    • 1970-01-01
    • 2015-01-21
    • 1970-01-01
    • 2015-05-08
    • 2020-01-22
    相关资源
    最近更新 更多