【问题标题】:Doctrine 2.2/Symfony 2.2: Persisting an entity with a composite foreign keyDoctrine 2.2/Symfony 2.2:使用复合外键持久化实体
【发布时间】:2013-08-23 12:37:03
【问题描述】:

我必须首先确定我是 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...
}

这两个表都是由数据库中的教义正确生成的。但是,尽管这应该是微不足道的,但我终其一生都找不到在这种情况下正确且成功的持久化操作的单个示例。

我尝试做的是:

    $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() 一起使用,而不需要像实际从数据库中检索完整对象那样的长度?

【问题讨论】:

  • 据我所知(限定任何可能的公牛).. 当您调用 ->find(1) 时,它会延迟加载对象而不是完全加载它。然后,当您将其传递给 Role() 对象时,它会从对象的代理版本中获取所需的内容,在这方面,它将是 id(而不是整个对象)。创建对象后,您需要调用persist(将对象排队等待数据库),然后刷新以将队列推送到数据库。以正确的方式使用它可确保您连接正确的对象,而不是使用随机的、可能不正确的 id 的新对象。

标签: php mysql sql symfony doctrine


【解决方案1】:

试试这个

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

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

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

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

【讨论】:

  • 已经尝试过了,正如我在描述末尾所说的那样。导致重复错误。无论如何,我不想保留问题类型,因为它已经存在于数据库中。我在这里不能做的是定义我的新 $role 条目应该使用的 issue_type 的(已经持久化的)外键。
  • 我更新了代码试试看它是否有效?由于$issueType 已经存在,请尝试获取它check the documentation here
  • 它有效,谢谢!但我有一种感觉,这不是最佳解决方案;这是对数据库的附加 SQL 请求,如果不使用 Doctrine,我会避免使用它。因此,我怀疑有更好的方法来做到这一点。
  • 我显然没有足够的“声誉”来做到这一点,抱歉。实际上这是我在这里的第一篇文章。
  • 我都读完了,但不是这么说的。它说每个人都可以创建/回答问题,但没有关于投票赞成或反对。如果您谈论将您的答案设置为我接受的答案,我更愿意在此之前等待其他答案。我告诉你,网站就是不让我投票,真的没办法。所以让我们暂时放下它,不要再用这种愚蠢的辩论来淹没答案。
【解决方案2】:

我知道这是一篇旧文章,但是……

只是添加到 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) 的代理,这是您保存角色实体所需的全部内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-13
    • 2013-03-12
    • 2014-01-18
    • 2012-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多