通过刷新上的外部实体异常来获得教义的OneToOne身份 [英] Doctrine OneToOne identity through foreign entity exception on flush

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

问题描述

我有 User UserProfile 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,并且没有其他列可以建立这种关系(文档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.

我想要的是UserProfile始终是在构造函数中与User一起创建的,但是如果这样做,则会出现以下异常:

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

Doctrine\ORM\ORMInvalidArgumentException:类型为'AppBundle\Entity\UserProfile'(AppBundle\Entity\UserProfile)的给定实体@ 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 Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="AppBundle\Entity\UserRepository")
 * @ORM\Table(name="users")
 */
class User
{
    /**
     * @var int
     *
     * @ORM\Column(name="uid", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * It's NULL at first, I create it later (after saving User).
     * 
     * @var UserProfile|null
     *
     * @ORM\OneToOne(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:
        //
        // Doctrine\ORM\ORMInvalidArgumentException: 
        // The given entity of type 'AppBundle\Entity\UserProfile' 
        // (AppBundle\Entity\UserProfile@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 Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(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
     *
     * @ORM\Id
     * @ORM\OneToOne(targetEntity="User", inversedBy="profile")
     * @ORM\JoinColumn(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.

Update2:
我知道它的含义是您希望实现的目标,但是通过设计,您不应在实体中移动此逻辑。实体应该代表尽可能少的逻辑,因为它们代表了您的模态。

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

但是,您应该考虑创建一个包含实体管理器的userService,并使其负责创建,链接和持久化用户+ userProfile实体。

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

这篇关于通过刷新上的外部实体异常来获得教义的OneToOne身份的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆