2013-08-23 174 views
1

我必须先确定我是一个总的初来乍到的教义,尽管我有足够的了解SQL和PHP/Symfony的2学说2.2/2.2的Symfony:坚持实体与复合外键

所以,我创建关联到一个SQL表这个问题类型的实体:

/** 
* IssueType 
* 
* @ORM\Table() 
* @ORM\Entity(repositoryClass="Blog\Bundle\CoreBundle\Entity\IssueTypeRepository") 
*/ 
class IssueType 
{ 
    /** 
    * @var integer 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    */ 
    private $id; 

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

    // Getters, setters... 
} 

我填充它,这样的内容说,现在的表是:

id | name 
1 | Bande dessinée 
2 | Livre 
3 | Film 
4 | Disque 

现在我有这个其他实体,角色,它使用复合键,由一个普通的字符串(名称)和外键(ID从问题类型)的:

/** 
* Role 
* 
* @ORM\Table() 
* @ORM\Entity(repositoryClass="Blog\Bundle\CoreBundle\Entity\RoleRepository") 
*/ 
class Role 
{ 
    /** 
    * @var IssueType 
    * 
    * @ORM\ManyToOne(targetEntity="Blog\Bundle\CoreBundle\Entity\IssueType") 
    * @ORM\JoinColumn(nullable=false) 
    * @ORM\Id 
    */ 
    private $issueType; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="name", type="string", length=255) 
    * @ORM\JoinColumn(nullable=false) 
    * @ORM\Id 
    */ 
    private $name; 

    // Getters, setters... 
} 

两个表是通过数据库中的教义正确生成。然而,尽管这应该是微不足道的,但我不能在我的生活中找到一个在这种情况下正确和成功坚持运作的例子。

我尝试做的是以下几点:

$manager = $this->getDoctrine()->getManager(); 

    $issueType = new IssueType(); 
    $issueType->setId(1); 

    $role = new Role(); 
    $role->setIssueType($issueType); 
    $role->setName('Dessinateur'); 

    $manager->persist($role); 
    $manager->flush(); 

我这样尝试坚持以下几点:

Role: { 
    IssueType: {id: 1, name: ''}, 
    name: 'Dessinateur', 
} 

而我得到的是这个讨厌的例外:

Entity of type Blog\Bundle\CoreBundle\Entity\Role has identity through a foreign entity Blog\Bundle\CoreBundle\Entity\IssueType, however this entity has no identity itself. You have to call EntityManager#persist() on the related entity and make sure that an identifier was generated before trying to persist 'Blog\Bundle\CoreBundle\Entity\Role'. In case of Post Insert ID Generation (such as MySQL Auto-Increment or PostgreSQL SERIAL) this means you have to call EntityManager#flush() between both persist operations. 

我明白它要我坚持第一个外国实体,但我不想这样做,因为外国问题类型ID#1已经存在于数据库中,因此不需要持久化。当我没有在注释中指定任何'级联'属性时,它怎么能问我?

BTY我试过,因为它说,它预计结束与重复的输入错误。

那么,我该怎么做才能使学说理解外国问题类型不应该被持续?

编辑

artmees提出了以下解决方案,工作正常:

$manager = $this->getDoctrine()->getManager(); 

$issueType = $manager->getRepository('BlogCoreBundle:IssueType')->find(1); 

$role = new Role(); 
$role->setIssueType($issueType); 
$role->setName('Dessinateur'); 

$manager->persist($role); 
$manager->flush(); 

然而,这意味着提高到能够在不使用原则就可以避免数据库的额外请求。由于我已经知道要使用的外部标识,是否有任何方法可以直接使用persist(),而不需要像从数据库中实际检索完整对象那样的长度?

+0

据我所知(限定任何可能的公牛)。当你调用' - > find(1)'时,懒惰加载对象而不是完全加载它。当你将它传递给'Role()'对象时,它从对象的代理版本中获得它所需的东西,在这方面它将是id(而不是整个对象)。 创建对象后,您需要调用persist(将对象排成数据库),然后刷新以将队列推送到数据库。正确使用它可以确保您将正确的对象而不是新鲜的对象与随机的,可能不正确的ID连接起来。 – qooplmao

回答

1

试试这个

$manager = $this->getDoctrine()->getManager(); 

$issueType = $manager->find('IssueTypeRepository', 1); 

$role = new Role(); 
$role->setIssueType($issueType); 
$role->setName('Dessinateur'); 

$manager->persist($role); 
$manager->flush(); 
+0

已经尝试过了,正如我在描述结束时所说的那样。导致重复错误。无论如何,我不想坚持问题类型,因为它已经存在于数据库中。 我不能在这里做的是定义我的新$角色条目应该使用的issue_type的(已经存在的)外键。 – Zephyr

+0

我更新了代码试试看它是否有效? 因为'$ issueType'已经存在请尝试获取它[在此处查看文档](http://docs.doctrine-project.org/en/2.0.x/reference/working-with-objects.html#querying) –

+0

它的工作原理,谢谢!但我有一种感觉,这不是最佳解决方案;这是对数据库的额外的SQL请求,如果不使用Doctrine,我会避免这种请求。因此,我怀疑有更好的方法来做到这一点。 – Zephyr

0

我知道这是一个老的文章,但...

只需添加到artmees答案,如果你知道ID和你只是想插入,你不需要加载实体,只需使用参考。

$manager = $this->getDoctrine()->getManager(); 

$issueType = $manager->getReference('BlogCoreBundle:IssueType',1); 

$role = new Role(); 
$role->setIssueType($issueType); 
$role->setName('Dessinateur'); 

$manager->persist($role); 
$manager->flush(); 

这将创建一个具有该ID(1)的代理,这是您保存角色实体所需的全部内容。