【问题标题】:Using generatedvalue from parent entity使用来自父实体的生成值
【发布时间】:2020-01-18 22:52:39
【问题描述】:

我的项目中有两个使用 Doctrine 的实体:

class User
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    private $user_id;

    /**
     * @ORM\Column(type="string")
     */
    private $username;

    /**
     * @ORM\Column(type="string")
     */
    private $password;

    /**
     * @ORM\OneToOne(targetEntity="UserProfile", cascade={"persist", "remove"})
     * @ORM\JoinColumn(name="user_id", referencedColumnName="user_id", unique=true)
     * @var UserProfile
     */
    private $profile;

    //...
}

class UserProfile
{
    /**
     * @ORM\Id
     * @ORM\OneToOne(targetEntity="User")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="user_id")
     */
    private $user;

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     */
    private $user_id;

    /**
     * @ORM\Column(type="string")
     */
    private $first_name = '';

    /**
     * @ORM\Column(type="string")
     */
     private $last_name = '';

     //...
}

我正在尝试使用以下方法在数据库中生成新行:

$user = new User();
$user->setUsername('test');
$user->setEmail('test@example.com');
$user->setPassword(password_hash('password', PASSWORD_BCRYPT));

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

$userProfile = new UserProfile();
$userProfile->setFirstName('test');
$userProfile->setLastName('user');

$user->setProfile($userProfile);

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

这似乎与此处的示例相似: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/tutorials/composite-primary-keys.html#use-case-2-simple-derived-identity

这会引发错误:

致命错误:未捕获的 Doctrine\ORM\ORMException: Entity of type App\Entity\UserProfile 缺少为字段“用户”分配的 ID。这 此实体的标识符生成策略需要 ID 字段 在调用 EntityManager#persist() 之前填充。如果你想 自动生成的标识符,而不是您需要调整 相应的元数据映射。在 /home/site/vendor/doctrine/orm/lib/Doctrine/ORM/ORMException.php on 第 87 行

如果我添加一个没有 UserProfile 的用户,这工作正常,我会在数据库中获得一行,其中 user_id 是从 MySQL 自动增量生成的。创建新配置文件时如何让 UserProfile 使用新创建的 user_id?

我是不是把关联的事情复杂化了?我应该只在 UserProfile 上创建一个 setUserId() 方法吗?

【问题讨论】:

  • 你能把User::setProfile()函数的代码贴出来吗?
  • 没什么特别的:public function setProfile(UserProfile $profile) : self { $this->profile = $profile; return $this; }

标签: php doctrine-orm


【解决方案1】:

UserUserProfile 实体之间的关系保留在 UserProfile::user 属性上,但是,当您调用 User::setProfile() 时,您并没有设置该属性。

将您的 User::setProfile() 函数更改为以下内容:

function setProfile(UserProfile $profile): self
{
    $profile->setUser($this);
    $this->profile = $profile;

    return $this;
}

【讨论】:

  • 感谢您的建议,但它会导致类似的错误,尽管现在它会抱怨:UserProfile is missing an assigned ID for field 'user_id'. The identifier generation strategy for this entity requires the ID field to be populated before EntityManager#persist() is called. If you want automatically generated identifiers instead you need to adjust the metadata mapping accordingly. in /home/ddc/vendor/doctrine/orm/lib/Doctrine/ORM/ORMException.php on line 87
  • 在您的代码中,您调用了两次$em->persist($user);,而不是$em->persist($userProfile);
  • 将其更改为 $em->persist($userProfile); 不会更改错误。无论如何,该关联应该从 user -> userProfile 级联。
  • 你验证过你的关系吗?
  • 我刚跑了orm:validate-schema,它抱怨我在UserProfile 中有$user 字段作为ID。我删除了它并验证了该工具。但是会抛出同样的错误。
【解决方案2】:

您的映射无效。验证您的架构 - 缺少 mappedByinversedBy。当您修复映射时,这将按预期工作。

在 Symfony 中验证模式:

bin/console doc:sch:val

在采埃孚:

php public/index.php orm:schema-tool:validate

【讨论】:

  • ./vendor/bin/doctrine orm:validate-schema 说它是正确的(我没有使用框架)。此外,学说网站上的示例也没有提到 mappedBy 或 inversedBy。我之前尝试过添加这些,但没有帮助。
  • 无论如何,您的架构有问题。为什么在两个实体中都需要 $user_id 属性,作为 Id 大声笑的一部分?这没有任何意义。仅保留User 实体中的$profileUserProfile 实体中的$user,并使用用户上的inversedBy 和配置文件上的mappedBy 将它们链接在一起。从两个实体中删除不必要的 $user_id 属性。使用 OneToOne 关系时,您也不需要“唯一”设置,因为它是默认设置的。修复您的映射,更新您的问题,然后我们可以继续。不要考虑数据库,专注于模型
【解决方案3】:

感谢@emix 和@fubar,他们都为解决方案做出了贡献。这最终奏效了:

class User
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $user_id;

    /**
     * @ORM\Column(type="string")
     */
    private $username;

    /**
     * @ORM\Column(type="string")
     */
    private $password;

    /**
     * @ORM\OneToOne(targetEntity="UserProfile", mappedBy="user", cascade={"persist", "remove"})
     * @var UserProfile
     */
    private $profile;

    //...

    public function setProfile(UserProfile $profile) : self
    {
        $profile->setUser($this);

        $this->profile = $profile;

        return $this;
    }
}

class UserProfile
{
    /**
     * @ORM\Id
     * @ORM\OneToOne(targetEntity="User", inversedBy="profile")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="user_id")
     */
    private $user;

    /**
     * @ORM\Column(type="string")
     */
    private $first_name = '';

    /**
     * @ORM\Column(type="string")
     */
     private $last_name = '';

     //...
}

这涉及从 UserProfile 实体中删除 $user_id 并将 inversedBy 参数添加到 OneToOne。

User 实体中删除 JoinColumn 并修复 setProfile() 的设置器,以便在 UserProfile 实体上设置 $user

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-30
    • 1970-01-01
    • 1970-01-01
    • 2019-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多