Doctrine 2.2 / Symfony 2.2:使用复合外键保持实体

时间:2013-08-23 12:37:04

标签: php mysql sql symfony doctrine

我必须首先确定我是Doctrine的新手,尽管我对SQL和PHP / Symfony 2了解得足够多。

所以,我创建了一个与SQL表关联的IssueType实体:

/**
 * 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

现在我有另一个实体Role,它使用复合键,由常规字符串(名称)和外键(来自IssueType的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...
}

这两个表都是由数据库中的doctrine正确生成的。然而,虽然它应该是微不足道的,但我不能在我的生活中找到一个正确和成功的持续操作的例子。

我尝试做的是以下内容:

    $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我无论如何都试着按照它的说法去做,并且预计最终会出现重复的输入错误。

那么,我应该怎样做才能让Doctrine明白外国问题类型不应该被保留?

修改

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

然而,这意味着向数据库发出额外请求,如果不使用Doctrine,则可以避免这种请求。由于我已经知道要使用的外部Id,有没有办法直接使用persist(),而不需要实际从数据库中检索完整对象的长度?

2 个答案:

答案 0 :(得分:1)

试试这个

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

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

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

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

答案 1 :(得分: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)的代理,这是保存角色实体所需的全部内容。