将实体添加到ManytoMany上的Doctrine PersistentCollection,而不会导致重复条目完整性约束违规

时间:2018-04-20 10:13:27

标签: php symfony doctrine

所以我有两个实体 - 用户和县。

许多用户可以拥有多个县,反之亦然,即它有多对多的关系:

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="county")
 * @ORM\Entity(repositoryClass="App\Repository\CountyRepository")
 */
class County
{
    /**
     * Many counties can have many users assigned
     *
     * @ORM\ManyToMany(targetEntity="App\Entity\User", mappedBy="counties")
     */
    protected $users;

    /**
     * @return mixed
     */
    public function getUsers()
    {
        return $this->users;
    }

    /**
     * @param mixed $users
     */
    public function setUsers($users): void
    {
        $this->users = $users;
    }
}
namespace App\Entity;

use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Mapping as ORM;

/**
 * Class User
 *
 * @package App\Entity
 *
 * @ORM\Entity
 * @ORM\Table("users")
 */
class User
{
    /**
     * Many users can be assigned to many counties
     *
     * @ORM\ManyToMany(targetEntity="App\Entity\County", inversedBy="users")
     * @ORM\JoinTable(name="users_counties")
     */
    protected $counties;

    /**
     * @param County $county
     */
    public function addCounty(County $county)
    {
        if (empty($this->getCounties())) {
            $this->setCounties([$county]);
        } else {
            if (!$this->getCounties()
                      ->contains($county)) {
                $this->getCounties()
                     ->add($county)
                ;
            }
        }
    }

    /**
     * @return PersistentCollection|null
     */
    public function getCounties()
    {
        return $this->counties;
    }

    /**
     * @param mixed $counties
     */
    public function setCounties($counties): void
    {
        $this->counties = $counties;
    }
}

请注意addCounty()实体上的User方法。

我想要的只是将一个实体添加到集合中,如果它还不是它的一部分。

我这样做而不是:

/**
 * @param County $county
 */
public function addCounty(County $county)
{
    $this->county[] = $county
    // OR
    $this->getCounties()->add($county)
}

由于这些方式会导致SQL错误,例如:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '42-22' for key 'PRIMARY'

现在 - 错误是有道理的,我得到了如何避免它,如上所示。

然而,我觉得这肯定是在dorctrine的ManytoMany关系中的一个共同挑战,所以我想知道是否有更好的方法来让它得到教条来隐含地处理这个问题。场景?

注意 - 我已经看过" Symfony doctrine Many to Many Integrity constraint violation: 1062 Duplicate entry"回答,但只是觉得应该有一个更好的方法来解决这个问题并获得理论来自动处理这个: - )

2 个答案:

答案 0 :(得分:1)

上述方法没有错:

public function addCounty(County $county)
{
    if (empty($this->getCounties())) {
        $this->setCounties([$county]);
    } else {
        if (!$this->getCounties()
                  ->contains($county)) {
            $this->getCounties()
                 ->add($county)
            ;
        }
    }
}

根据doctrine doc

  

Doctrine不会检查您是否使用已存在的主键重新添加实体,或者是否将实体添加到集合中两次。如果您知道可能发生唯一约束失败,则必须在调用$ em-> flush()之前在代码中自行检查这两个条件。

因此,您正确地检查实体是否已经是拥有方的集合的一部分,如果没有,则添加它。

通过使用indexBy属性,替代方式使用更少的代码行来执行此操作:

 /**
 * Many users can be assigned to many counties
 *
 * @ORM\ManyToMany(targetEntity="AppBundle\Entity\County", inversedBy="users", indexBy="id")
 * @ORM\JoinTable(name="users_counties")
 */
protected $counties;

对于集合, indexBy =" id" ,然后您可以:

public function addCounty(County $county)
{
    $this->counties[$county->getId()] = $county;
}

答案 1 :(得分:0)

这应该有效:

/**
* @param County $county
*/
public function addCounty(County $county)
{
    // Here you make sure that the $county is removed if it where present
    $this->counties->removeElement($county);

    // Now you add it
    $this->counties->add($county);
}