我有User
和UserProfile
与OneToOne相关的Doctrine ORM实体。它们应该始终成对存在,没有User
没有UserProfile
。
用户应从自动增量获取其ID,而UserProfile应具有用户ID。所以它们都应该具有相同的ID,并且没有其他列来设置关系(Doctrine docs: Identity through foreign Entities)。
UserProfile的id同时是主键(PK)和外键(FK)。
我设法设置了它,但它要求首先保存用户,并且只在以后创建UserProfile并在单独的步骤中保存。
我想要的是UserProfile总是在构造函数中使用User创建,但是如果我这样做,我会得到以下异常:
Doctrine\ORM\ORMInvalidArgumentException: The given entity of type 'AppBundle\Entity\UserProfile' (AppBundle\Entity\UserProfile@0000000052e1b1eb00000000409c6f2c) has no identity/no id values set. It cannot be added to the identity map.
请参阅下面的代码 - 它有效,但不是我想要的方式。 php评论显示了我想要实现的目标。
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;
}
}
答案 0 :(得分:1)
请记住,实体对象需要由EntityManager保存。 仅仅将该类作为对另一个类的引用并不会使entityManager意识到两个类都存在的事实。
您应该将实际的userProfile持久保存到EntityManager,以便能够保存关系。
因负面评论而更新:
请阅读Doctrine文档......你应该坚持下去!
以下示例是本章User-Comment示例的扩展。假设在我们的应用程序中,每当他写第一条评论时都会创建用户。在这种情况下,我们将使用以下代码:
<?php
$user = new User();
$myFirstComment = new Comment();
$user->addComment($myFirstComment);
$em->persist($user);
$em->persist($myFirstComment);
$em->flush();
即使您持有包含新注释的新用户,如果您删除了对EntityManager#persist($ myFirstComment)的调用,此代码也会失败。 Doctrine 2不会将持久化操作级联到所有新的嵌套实体。
<强> UPDATE2:强> 我理解你想要完成的是什么,但是按照设计你不应该在你的实体中移动这个逻辑。实体应该代表尽可能少的逻辑,因为它们代表了你的模态。
说实话,我相信你可以完成你想做的事情:
$user = new User();
$profile = $user->getProfile();
$objectManager->persist($user);
$objectManager->persist($profile);
$objectManager->flush();
但是,您应该考虑创建一个包含entitymanager的userService,并使其负责创建,链接和持久化user + userProfile实体。