沃梦达 / 编程问答 / php问题 / 正文

Doctrine OneToOne 身份通过刷新时的外国实体异常

Doctrine OneToOne identity through foreign entity exception on flush(Doctrine OneToOne 身份通过刷新时的外国实体异常)

本文介绍了Doctrine OneToOne 身份通过刷新时的外国实体异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有 UserUserProfile OneToOne 相关的 Doctrine ORM 实体.它们应该始终成对存在,没有 UserProfile 就不应该有 User.

I have User and UserProfile OneToOne–related Doctrine ORM entities. They should always exist as a pair, there should be no User without UserProfile.

用户应该从自动增量获取它的 id,而 UserProfile 应该有用户的 id.所以他们都应该有相同的 id 并且没有其他列来建立关系(Doctrine docs:通过外国实体进行身份验证).

User should get its id from autoincrement, while UserProfile should have User's id. So they both should have the same id and there is no other column to set up the relationship (Doctrine docs: Identity through foreign Entities).

UserProfile 的 id 同时是主键 (PK) 和外键 (FK).

UserProfile's id is both a primary key (PK) and foreign key (FK) at the same time.

我设法设置了它,但它要求先保存用户,然后才在单独的步骤中创建和保存 UserProfile.

I managed to set it up, but it requires that User is saved first and only later UserProfile is created and saved in a separate step.

我想要的是在构造函数中始终使用 User 创建 UserProfile,但如果我这样做,我会得到这个异常:

What I want is that UserProfile is always created with User, in the constructor, but if I do that, I get this exception:

DoctrineORMORMInvalidArgumentException:AppBundleEntityUserProfile"类型的给定实体 (AppBundleEntityUserProfile@0000000052e1b1eb00000000409c6f2c) 没有设置身份/没有 id 值.无法添加到身份映射中.

请看下面的代码——它可以工作,但不是我想要的方式.php 注释显示了我想要实现的目标.

Please see code below – it works, but not the way I want. The php comments show what I want to achieve.

Test.php:

/**
 * It works, both saving and loading.
 * BUT, it requires that I create and save UserProfile 
 * in a separate step than saving User step.
 */

// create and save User
$user = new User();
$objectManager->persist($user);
$objectManager->flush();

// create and save UserProfile (this should be unnecessary)
$user->createProfile()
$objectManager->flush();

User.php:

use DoctrineORMMapping as ORM;

/**
 * @ORMEntity(repositoryClass="AppBundleEntityUserRepository")
 * @ORMTable(name="users")
 */
class User
{
    /**
     * @var int
     *
     * @ORMColumn(name="uid", type="integer")
     * @ORMId
     * @ORMGeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * It's NULL at first, I create it later (after saving User).
     * 
     * @var UserProfile|null
     *
     * @ORMOneToOne(targetEntity="UserProfile", mappedBy="user", cascade="persist")
     */
    private $profile = null;

    public function __construct()
    {
        // I want to create UserProfile inside User's constructor,
        // so that it is always present (never NULL):
        //$this->profile = new UserProfile($this);

        // but this would give me error:
        //
        // DoctrineORMORMInvalidArgumentException: 
        // The given entity of type 'AppBundleEntityUserProfile' 
        // (AppBundleEntityUserProfile@0000000058af220a0000000079dc875a)
        // has no identity/no id values set. It cannot be added to the identity map.
    }

    public function createProfile()
    {
        $this->profile = new UserProfile($this);
    }   
}

UserProfile.php:

use DoctrineORMMapping as ORM;

/**
 * @ORMEntity
 * @ORMTable(name="profiles")
 */
class UserProfile
{
    /**
     * – UserProfile's "uid" column points to User's "uid" column
     * – it is PK (primary key)
     * - it is FK (foreign key) as well
     * – "owning side"
     *
     * @var User
     *
     * @ORMId
     * @ORMOneToOne(targetEntity="User", inversedBy="profile")
     * @ORMJoinColumn(name="uid", referencedColumnName="uid", nullable=false)
    */
    private $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }    
}

测试应用:https://github.com/MacDada/DoctrineOneToOneTest

推荐答案

请记住,实际对象需要由E​​ntityManager保存.仅将类作为对另一个类的引用不会使 entityManager 意识到这两个类都存在.

Please keep in mind that the actual object needs to be saved by the EntityManager. Just giving the class as reference to the other class does not make the entityManager aware of the fact both classes exists.

您应该将实际的 userProfile 持久化到 EntityManager 以便能够保存关系.

You should persist the actual userProfile to the EntityManager to be able to save the relation.

因为负面评论而更新:

请阅读 Doctrine 文档...你应该坚持下去!

Please read the Doctrine docs... You should persist!

以下示例是本章用户评论示例的扩展.假设在我们的应用程序中,每当他写下他的第一条评论时都会创建一个用户.在这种情况下,我们将使用以下代码:

The following example is an extension to the User-Comment example of this chapter. Suppose in our application a user is created whenever he writes his first comment. In this case we would use the following code:

<?php
$user = new User();
$myFirstComment = new Comment();
$user->addComment($myFirstComment);

$em->persist($user);
$em->persist($myFirstComment);
$em->flush();

即使您保留一个包含我们的新评论的新用户,如果您删除对 EntityManager#persist($myFirstComment) 的调用,此代码也会失败.原则 2 也不会将持久化操作级联到所有新的嵌套实体.

Even if you persist a new User that contains our new Comment this code would fail if you removed the call to EntityManager#persist($myFirstComment). Doctrine 2 does not cascade the persist operation to all nested entities that are new as well.

更新 2:我了解您希望完成什么,但根据设计,您不应该在您的实体中移动此逻辑.实体应该代表尽可能少的逻辑,因为它们代表您的模式.

Update2: I understand what it is you wish to accomplish, but by design you should not move this logic within your entities. Entities should represent as less logic as possible, since they represent your modal.

话虽如此,我相信你可以像这样完成你想做的事情:

Have that said, I believe you could accomplish what you are trying to do like this:

$user = new User();
$profile = $user->getProfile();
$objectManager->persist($user);
$objectManager->persist($profile);
$objectManager->flush();

但是,您应该考虑创建一个包含 entitymanager 的 userService,并让其负责创建、链接和持久化 user + userProfile 实体.

You should however consider creating a userService containing the entitymanager and make that responsible for creating, linking and persisting the user + userProfile entity.

这篇关于Doctrine OneToOne 身份通过刷新时的外国实体异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:Doctrine OneToOne 身份通过刷新时的外国实体异常

基础教程推荐