在doctrine 2中的ManyToMany关联中未更新连接表

时间:2011-09-09 06:59:06

标签: doctrine-orm

我有两个实体SlaplansSlaholidays以及一个联接表slaplans_slaholidays。 创建两个Slaholidays对象后,我将它们都保留,将它们添加到Slaplans并刷新。问题是只更新slaplansslaholidays表,但连接表不是。

Slaplans实体:

<?php
namespace ZC\Entity;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Slaplans
 *
 * @Table(name="slaplans")
 * @Entity(repositoryClass="Repositories\Slaplans")
 */
class Slaplans
{         
   /*
    * @ManyToMany(targetEntity="Slaholidays",inversedBy="plans", cascade={"ALL"})
    * @JoinTable(name="slaplans_slaholidays",
    * joinColumns={@JoinColumn(name="slaplanid" ,referencedColumnName="slaplanid")},
    * inverseJoinColumns={@JoinColumn(name="slaholidayid" ,referencedColumnName="slaholidayid")})
    * }
     */
    private $holidays;

    public function __construct()
    {

        $this->holidays = new \Doctrine\Common\Collections\ArrayCollection();
    }

public function getHolidays() {
    return $this->holidays;
}
public function setHolidays($holidays)
{
    $this->holidays=$holidays;

}
/*public function addHoliday($holiday) {

    $this->holidays[]=$holiday;
}*/
}

Slaholidays实体:

<?php
namespace ZC\Entity;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Slaholidays
 *
 * @Table(name="slaholidays")
 * @Entity(repositoryClass="Repositories\Slaholidays")
 */
class Slaholidays
{
    /**
     * @var integer $slaholidayid
     *
     * @Column(name="slaholidayid", type="integer", nullable=false)
     * @Id
     * @GeneratedValue(strategy="IDENTITY")
     */
    private $slaholidayid;

    /*
     *  @ManyToMany(targetEntity="Slaplans",mappedBy="holidays", cascade={"ALL"})
     */
    private $plans;

    /*public function getPlans(){
        return $this->plans;
    }*/
}

持久保存实体的代码:

$allholidays=array();
$holiday=$this->_em->getRepository('ZC\Entity\Slaholidays')->find($value);
$holiday=new ZC\Entity\Slaholidays();
//..sets holiday fields here
$this->_em->persist($holiday);
$allholidays[]=$holiday;

$slaplan->setHolidays($allholidays);
foreach ($slaplan->getHolidays() as $value) {
    $this->_em->persist($value);
}
$this->_em->persist($slaplan);
$this->_em->flush();

2 个答案:

答案 0 :(得分:0)

您的代码中有两个问题:

第一个:你将每个Slaholiday持续两次:首先是

$this->_em->persist($holiday);

,第二个

foreach ($slaplan->getHolidays() as $value) {
    $this->_em->persist($value);
}

实际上没有问题,因为在调用flush之前它们实际上并没有保留在数据库中,但无论如何,您不需要foreach

您的联接表未更新的原因是$slaplan->setHolidays方法。您正在使用$slaplan->holidays初始化ArrayCollection(这是正确的),并在setHolidays中将其设置为输入参数($allholidays Array,这是不对。)

因此,正确的方法是使用ArrayCollection的{​​{3}}方法

public function setHolidays($holidays)
{
    //$this->holidays->clear(); //clears the collection, uncomment if you need it
    foreach ($holidays as $holiday){
        $this->holidays->add($holiday);
    }
}

OR

public function addHolidays(ZC\Entity\Slaholiday $holiday)
{
    $this->holidays->add($holiday);
}

public function clearHolidays(){
    $this->holidays->clear();
}
//..and in the working script...//

//..the rest of the script
$this->_em->persist($holiday);
//$slaplan->clearHolidays(); //uncomment if you need your collection cleaned
$slaplan->addHOliday($holiday);

答案 1 :(得分:0)

虽然Doctrine会检查关联的拥有方是否存在需要保留的内容,但保持关联的两端同步仍然很重要。

我建议双方都要获取,添加和删除(没有设置)方法,如下所示:

class Slaplans
{
    public function getHolidays()
    {
        return $this->holidays->toArray();
    }

    public function addHoliday(Slaholiday $holiday)
    {
        if (!$this->holidays->contains($holiday)) {
            $this->holidays->add($holiday);
            $holiday->addPlan($this);
        }
        return $this;
    }

    public function removeHoliday(Slaholiday $holiday)
    {
        if ($this->holidays->contains($holiday)) {
            $this->holidays->removeElement($holiday);
            $holiday->removePlan($this);
        }
        return $this;
    }
}

Slaplan中执行相同操作。

现在当你向Slaplan添加一个Slaholiday时,Slaplan也将自动添加到Slaholiday中。删除也是如此。

所以现在你可以这样做:

$plan = $em->find('Slaplan', 1);

$holiday = new Slaholiday();
// set data on $holiday
// no need to persist $holiday, because you have a cascade={"ALL"} all on the association

$plan->addHoliday($holiday);
// no need to persist $plan, because it's managed by the entitymanager (unless you don't use change tracking policy "DEFERRED_IMPLICIT" (which is used by default))
$em->flush();

PS:不要在关联的两边使用cascade。这会使事情变得比必要的慢,并且在某些情况下会导致错误。如果先创建一个Slaplan,然后将Slaholidays添加到它,保留Slaplan中的cascade并从Slaholiday中删除它。