ManyToOne 原则仅更改连接实体的值而不是创建新实体

ManyToOne doctrine only changes the values of connected Entity instead of creating an new one

我有一个大(简单)问题。

我有一个用户实体,其地理位置 属性 作为多对一关系

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;

/**
 * User
 */
class User implements AdvancedUserInterface, \Serializable
{
   /**
    * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Location", cascade= {"persist"})
    * @ORM\JoinColumn(name="location_id", referencedColumnName="id")
    */
    private $geolocation;

我有一个像这样的位置实体:

/**
 * Location
 *
 * @ORM\Table(name="location")
 * @ORM\Entity(repositoryClass="AppBundle\Entity\Repository\LocationRepository")
 */
class Location
{

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @Assert\NotBlank()
     * @ORM\Column(name="latitude", type="float", scale=12, precision=18)
     */
    private $latitude;

    /**
     * @var string
     *
     * @Assert\NotBlank()
     * @ORM\Column(name="longitude", type="float", scale=12, precision=18)
     */
    private $longitude;

    /**
     * @var string
     *
     * @Assert\NotBlank()
     * @ORM\Column(name="address", type="string", length=255)
     */
    private $address;

现在的问题是,我想更改(更新)用户的位置。为此,我有一个 FormType:

$builder->add('geolocation',  'jquerygeolocation', array();

'jquerygeolocation' FormType 是使用

创建的 FormType
data_class' => 'AppBundle\Entity\Location'

但是当我想更改(更新)用户位置时,我遇到了一个大问题。如果该位置甚至不在数据库中,我想保留一个新位置,并且我想将现有位置与用户连接。但是学说只会改变连接位置的值。

例如:

之前:

之后:

可以看到,id是一样的。只有一个更新。没有我猜的逻辑。

有人可以帮我解决这个问题吗?

谢谢迈克尔。

有了这些关系,您通常会提供现有位置的选择列表和创建新位置的单独机制。通过在您的用户表单中嵌入位置实体表单,任何更新都将始终应用于已与用户关联的位置实体。

如果您希望它按照问题中的描述工作,您需要在您的控制器中(或者更好的是在控制器使用的业务逻辑服务中)编写一些自定义代码来处理它。

假设它是唯一标识位置的地址,那么您将需要这样的东西(在控制器中处理请求之后,以便您拥有包含提交数据的用户实例):

$em = $this->getDoctrine()->getManager();
$locationRepo = $em->getRepository('AppBundle:Location');
$location = $locationRepo->findOneByAddress($user->getGeolocation()->getAddress());

if (!$location)
{
    $location = new Location();
    $location->setLongitude($user->getGeolocation()->getLongitude());
    $location->setLatitude($user->getGeolocation()->getLatitude());
    $location->setAddress($user->getGeolocation()->getAddress());
    $em->persist($location);
}

$user->setLocation($location);
$em->flush($user);

很好。这正是我所猜测的。但解决方案并不像这样容易。除了您的解决方案之外,您还必须防止更新旧位置实体。否则旧值与新位置相同。为此,我在实体中使用了生命周期回调:

Location.php

/**
 * @ORM\PreUpdate
 */
public function preventUpdate(PreUpdateEventArgs $args)
{
        $address = $args->getOldValue('address');
        $latitude =$args->getOldValue('latitude');
        $longitude = $args->getOldValue('longitude');
        $locality = $args->getOldValue('locality');
        $country = $args->getOldValue('country');

        $locationArray = array(
            'address'   => $address,
            'latitude'  => $latitude,
            'longitude' => $longitude,
            'locality'  => $locality,
            'country'   => $country
        );

        $this->update($locationArray);
}

在 Location.php 实体中使用以下函数:

public function update($location)
{
    $data = $location;

    $this->address  = $data['address']  ?: null;
    $this->latitude = $data['latitude'] ?: null;
    $this->longitude = $data['longitude'] ?: null;
    $this->locality = $data['locality'] ?: null;
    $this->country = $data['country'] ?: null;
}

现在的问题是,我永远无法更新位置。 好的,我现在还不知道是否需要它。 但是,如果有没有这种消极方面的另一种解决方案,我将不胜感激。