【发布时间】:2021-12-28 17:59:59
【问题描述】:
我有以下两个实体 address 和 user 。 在我的一个控制器中,我有这个功能:
public function initAddressAction($idUser)
{
$em = $this->getDoctrine()->getManager();
$address = new Address();
/** @var User $user*/
$user= $em->getRepository('AppBundle:User' )->find($idUser);
if ($user!== null) {
$address->setUser($user);
dump($user); // #1
$addresses = $user->getAddresses()->toArray();
dump($user);die; // #2
...}
我的问题是为什么第一个转储会在地址字段中打印带有空数组的用户对象:
#collection: Doctrine\Common\Collections\ArrayCollection {#9487 ▼
-elements: []`
而第二个转储在地址字段中打印带有非空数组集合的用户对象(该数组中实际上有一个地址):
#collection: Doctrine\Common\Collections\ArrayCollection {#9487 ▼
-elements: array:1 [▼
0 => App\Entity\address{#81625 ▼`
用户:
/**
* @ORM\OneToMany(targetEntity="App\Entity\Address", mappedBy="user")
*/
private $addresses;
/**
* Set addresses
*
* @param Collection $addresses
*/
public function setAddresses($addresses)
{
$this->addresses= $addresses;
}
/**
* Get addresses
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getAddresses()
{
return $this->addresses;
}
/**
* Add address
*
* @param Address $address
* @return User
*/
public function addAddress(Address$address)
{
if (!$this->addresses->contains($address)) {
$this->addresses[] = $address;
}
return $this;
}
/**
* Remove address
*
* @param Address $address
*/
public function removeAddress(Address $address)
{
$this->addresses->removeElement($address);
}
地址:
/**
* @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="adresses")
* @ORM\JoinColumn(name="id_user", referencedColumnName="id_user", nullable=false)
*/
private $user
/**
* @return User
*/
public function getUser()
{
return $this->user;
}
/**
* @param User $user
*/
public function setUser($user)
{
$this->user= $user;
}
【问题讨论】:
-
这是延迟加载:Doctrine 不会在需要时加载集合中的对象。当调用集合上的方法时加载对象。所以,
dump($user)转储没有地址的用户,在调用getAddresses()->toArray()后,用户的地址从数据库中加载,添加到用户并在第二个转储中可见。 -
没错,这种情况下不会填写addresses属性。如果稍后在您的代码中,您确实使用了addresses 属性(例如,使用foreach 打印地址)地址将在代码中的该点加载。如果您稍后在代码中不使用该属性,该属性将保持为空,但地址仍在数据库中,因此它们不会丢失。基本上,您应该使用 User 对象,就好像它已经完全加载了它的地址一样,而不必担心何时以及是否加载了地址。
-
延迟加载只加载保存在数据库中的地址。如果要添加一个尚未保存到数据库中的新地址到用户的地址数组中,则需要使用 addAddress()。
-
只有用户的 $addresses 属性上的地址才会被延迟加载。要添加新地址,请将用户添加到具有
$address->setUser($user)的地址,这将设置关系的拥有方。然后用persist($address)和flush()保存地址。如果您在保存新地址后调用$addresses = $user->getAddresses()->toArray(),则$addresses 还将包含新添加的用户地址。 -
(你也可以调用
$user->addAddress($address)添加新地址,但是在addAddress()方法中你仍然需要$address->setUser($this),因为你总是需要设置关系。)
标签: symfony4