Doctrine 2 ArrayCollections - 我错过了什么吗?

时间:2014-07-22 19:08:46

标签: php symfony doctrine-orm

我有一种双向的多对一关系。我们选择FooBarFoo有以下内容:

class Foo
{
    /**
     * @ORM\OneToMany(targetEntity="Bar", mappedBy="foo", cascade={"all"}, orphanRemoval=true)
     */
    private $bars;

    public function __construct()
    {
        $this->bars = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * @param mixed $bars
     */
    public function setBars($bars)
    {
        $this->bars = $bars;
    }

    /**
     * @param Bar $bar
     */
    public function addBar(Bar $bar)
    {
        $this->bars->add($bar);
    }

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

Bar

class Bar
{
    /**
     * @ORM\Id()
     * @ORM\ManyToOne(targetEntity="Foo", inversedBy="bars")
     * @ORM\JoinColumn(name="foo_id", referencedColumnName="id", nullable=false)
     */
    protected $foo;

    /**
     * @param Foo $foo
     */
    public function setFoo(Foo $foo)
    {
        $this->foo = $foo;
    }

    /**
     * @return Foo
     */
    public function getFoo()
    {
        return $this->foo;
    }
}

好的,所以上面的课程,当我写:

$foo = new Foo();

$bar1 = new Bar();
$bar2 = new Bar();

$foo->addBar($bar1);
$foo->addBar($bar2);

并尝试坚持,我得到一个错误,关于每个Bar的foo属性是如何为空:

enter image description here

同样,如果我把它翻到:

$foo = new Foo();

$bar1 = new Bar();
$bar2 = new Bar();

$bar1->setFoo($foo);
$bar2->setFoo($foo);

我可以坚持,但是我的Foo新生成的PersistentCollection属性是空的:

enter image description here

这是预期的行为吗?我已经习惯了不同平台上的其他ORM在分配时连接双向关系,所以我不确定这对于Doctrine / PHP是否正常,或者我的注释是否搞砸了(上面的错误消息让我相信)。

所以,非常感谢任何帮助。

4 个答案:

答案 0 :(得分:1)

您需要设置关联的两面,例如

/**
 * @param Bar $bar
 */
public function addBar(Bar $bar)
{
    if(!$this->bars->contains($bar)) {
        $this->bars->add($bar);
        $bar->setFoo($this);
    }
}
----
/**
 * @param Foo $foo
 */
public function setFoo(Foo $foo)
{
    if($this->foo !== $foo) {
        $this->foo = $foo;
        $foo->addBar($this);
    }
}

目前你唯一设置协会的一方和Doctrine不会为你做其余的事。

如果您不想修改添加/删除方法,则必须

 $bar->setFoo($foo)
 $foo->addBar($bar)

每次你想要添加foo或bar

编辑:

如果您只想使用一面进行所有操作,请阅读owning/inverse side。也许它可以帮助解决你的问题。但我不确定它会在您的实体之间建立正确的双向链接。

答案 1 :(得分:1)

您的主要问题是,在添加条形图时,您没有在条形图中设置Foo。

要自动设置您可以执行以下操作(我还添加了一个检查,以查看是否已添加条形图并返回链条集)..

/**
 * Add bar
 *
 * @param Bar $bar
 * @return $this
 */
public function addBar(Bar $bar)
{
    if (!$this->bars->contains($bar)) {
        $this->bars->add($bar);
        $bar->setFoo($this)
    }

    return $this;
}

你可能应该摆脱setBars,因为我看到如果你使用set但没有使用数组集会导致问题。

另外你应该添加一个删除栏,这样你就不会每次都获取,删除,然后重置,比如..

/**
 * Remove bar
 *
 * @param Bar $bar
 * @return $this
 */
public function removeBar(Bar $bar)
{
    if ($this->bars->contains($bar)) {
        $this->bars->removeElement($bar);
        $bar->setFoo(null);
    }

    return $this;
}

这意味着您的setFoo需要能够接受空值..

/**
 * Set foo
 *
 * @param Foo $foo
 */
public function setFoo(Foo $foo = null)
{
    $this->foo = $foo;
}

答案 2 :(得分:0)

您收到的错误消息告诉您,如果不填写id字段,就无法保留实体。此外,您的Foo实体中似乎缺少id字段。

无论如何,id字段可能已存在于您的数据库中(由Doctrine自动生成),但未设置自动增量,因此在保留之前必须手动填充它。

尝试在您的实体中添加以下代码:

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

希望它有所帮助。

答案 3 :(得分:0)

将此添加到您的addBar功能中。你错过了后面的参考。从bar实体到foo实体

/**
* @param Bar $bar
*/
public function addBar(Bar $bar)
{
    $bar->setFoo($this);
    $this->bars->add($bar);
}