2014-07-22 56 views
1

我有一个双向的多对一关系。我们来用FooBarFoo有以下几点:Doctrine 2 ArrayCollections - 我错过了什么?

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是否正常,或者我的注释混乱了(上面的错误消息让我相信)。

所以,任何帮助将不胜感激。

+0

你试图坚持美孚你打电话之前setFoo? – Alex

+0

没有变化。 'PersistentCollection'仍为空 –

回答

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); 
    } 
} 

目前你唯一的设定关联的一侧,学说不为你做休息。

如果你不希望修改添加要添加一个富或酒吧

修改/删除你的方法来

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

每次:

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

+0

我认为我走在正确的轨道上。 'Bar'实际上是'Foo'和'Baz'之间的多对多关系的关联表,它包含一些元数据。现在,它给我一个关于Bar'没有自己身份的错误。它包含'Foo'和'Baz'的外键,但没有自己的ID。我不确定是否应该给它一个自己增加的自己的ID,或者如果我可以让它识别外部ID组合作为它自己的身份。对不起,我之前没有提到它。我在NDA下经营。 –

+0

看看[这个](http://docs.doctrine-project.org/en/latest/tutorials/composite-primary-keys.html),@ KevinM1。它有帮助吗? – AlixB

+0

不幸的是,错误依然存在。错误消息是:Bar​​类型的实体通过外部实体Foo具有身份,但是该实体本身没有身份。您必须在相关实体上调用EntityManager#persist(),并确保在试图保留“Bar”之前生成了一个标识符。如果生成后插入ID(例如MySQL自动递增或PostgreSQL SERIAL),这意味着您必须在两个持久操作之间调用EntityManager#flush()。 –

1

你的主要问题是,当你添加一个Bar时,你并没有在Bar中设置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; 
} 
0

你正在告诉一个实体不能没有填充被持久化的错误信息id字段。此外,它看起来像你在你的Foo实体中缺少id字段。

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

尝试在实体加入以下代码:

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

希望它能帮助。

+0

@Id定义在'protected $ foo;'的上面,它是一个有效的解决方案。 – AlixB

+0

默认使用''auto''策略,并且''@ORM \ Id()''是有效的 – ins0

0

将此添加到您的addBar函数。你错过了后卫。从bar实体到foo实体

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