共享主键的两个表上的一对一关系 [英] One to one relationship on two tables sharing primary key

查看:253
本文介绍了共享主键的两个表上的一对一关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望两个表 Person Address 共享其主键:

I want two tables, Person and Address, to share their primary key:

CREATE TABLE Person (id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY);
CREATE TABLE Address (personId INT UNSIGNED NOT NULL PRIMARY KEY);

我正在尝试对创建 Person ,您还为此创建了地址

I'm trying to model the idea that when you create a Person, you're also creating an Address for it.

我想出了以下映射:

class Person
{
    /**
     * @Id
     * @Column(type="integer")
     * @GeneratedValue
     */
    private $id;

    /**
     * @OneToOne(targetEntity="Address", cascade={"all"})
     * @JoinColumn(name="id", referencedColumnName="personId")
     */
    private $address;

    public function __construct() {
        $this->address = new Address($this);
    }
}

class Address
{
    /**
     * @Id
     * @OneToOne(targetEntity="Person")
     * @JoinColumn(name="personId", referencedColumnName="id")
     */
    private $person;

    public function __construct(Person $person) {
        $this->person = $person;
    }
}

当我尝试坚持时,我希望它会级联到地址,但出现以下异常:

When I try to persist Person, I would expect it to cascade to Address, but I get the following exception:

Doctrine\ORM\ORMException


Address类型的实体通过外国实体 Person 具有身份,
但是该实体本身没有身份。您必须在相关实体上调用
EntityManager#persist()并确保在尝试持久保存<$ c $之前已生成
标识符c>地址。
用于生成后插入ID(例如MySQL 自动递增
或PostgreSQL SERIAL ),这意味着您必须在两个持久操作之间调用 EntityManager#flush()

Entity of type Address has identity through a foreign entity Person, 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 Address. 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.

我不能显式调用 flush(),因为我没有显式调用 persist() ing Address ,相反,我期望 Person 可以级联持久保存 Address

I can't explicitly call flush(), because I'm not explicitly persist()ing Address, instead I'm expecting Person to cascade persist Address.

据我了解,Doctrine的工作是 flush()在适当的时候获得 id

So as far as I understand it, it should be Doctrine's job to flush() at the right moment to get the id.

这种一对一的关系在使用不同的关系时可以很好地层叠 Address auto_increment id(但后来我必须向人员添加 addressId )。

This one-to-one relationship cascades fine when using different auto_increment ids for both Person and Address (but then I have to add an addressId to Person).

我的目的是使他们共享相同的 id

My aim is to make them share the same id.

有可能吗?

推荐答案

在理论2.1中通过外国实体的身份

在您的方案中,您可以使用 @ManyToOne 代替 @OneToOne 关联。

In your scenario you can use @ManyToOne instead @OneToOne association.

当您保留拥有方时,关联将保留。在您的映射中,这是地址。更改您的映射,以便所有者具有外键,并且一切正常。

The association is persisted when you persist the owning side. In your mapping, that is the Address. Change your mapping so the owner has the foreign key and everything should work fine.

/**
 * @OneToOne(targetEntity="Address", cascade={"all"}, inversedBy="person")
 * @JoinColumn(name="id", referencedColumnName="personId")
 */
private $address;

换句话说,如果 Address 应该是人员,那么您必须将地址保留在第一位,以便保留关联。
如果您希望关联与 Person 保持一致,则应将 Person 标记为拥有方和地址方:

In other words, if Address should be owner by the Person then you must persist Address at first place to in order to persist the association. If you want the association to be persisted with Person, then you should mark the Person to be the owning side and Address to be the inverse side:

/**
 * @Id
 * @OneToOne(targetEntity="Person", inversedBy="address")
 * @JoinColumn(name="personId", referencedColumnName="id")
 */
private $person;

这篇关于共享主键的两个表上的一对一关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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