【问题标题】:Doctrine nullable one-to-one relationship still wants to create unique indexDoctrine 可为空的一对一关系仍要创建唯一索引
【发布时间】:2013-09-29 02:08:11
【问题描述】:

我有一个Person 实体,它与Location 表有两个关系(hometowncurrent)。这两个字段都可以为空,否则必须存在Location表中:

class Person {
.....
/**
 * @var Location
 * @ORM\OneToOne(targetEntity="Location")
 * @ORM\JoinColumn(name="hometown_id", referencedColumnName="id",nullable=true)
 **/
protected $hometown;

/**
 * @var Location
 * @ORM\OneToOne(targetEntity="Location")
 * @ORM\JoinColumn(name="current_id", referencedColumnName="id", nullable=true)
 **/     
 protected $current;
....
}

现在,我想根据doctrine:schema:update --dump-sql 输出更新我的数据库架构,但这会产生问题:

CREATE UNIQUE INDEX UNIQ_8D93D6494341EE7D ON person (hometown_id);
CREATE UNIQUE INDEX UNIQ_8D93D649B8998A57 ON person (current_id);

我无法定义这些索引,因为表中有多个空行。

你能帮帮我吗?

【问题讨论】:

    标签: php mysql sql symfony doctrine-orm


    【解决方案1】:

    OneToOne 关系是唯一的,因为这意味着只能将一个 person 分配给一个 location,将一个 location 分配给一个 person

    在您的场景中,您可能希望一个person 拥有多个位置,而一个location 可能拥有多个person(s)。这将是ManyToMany 关系。

    在 Doctrine 中,当您使用 ManyToMany 时,您将指定 Doctrine 将管理的 JoinTable(您不必为 JoinTable 创建实体)。 JoinTableManyToMany 分解为类似于OneToMany 的东西,例如一个person 到多个location(s),如下例所示。 JoinTable 将在应用时存储您想要的值。

    /**
     * @ORM\ManyToMany(targetEntity="Location")
     * @ORM\JoinTable(name="hometown_location",
     *      joinColumns={@ORM\JoinColumn(name="person_id", referencedColumnName="id", unique=true)},
     *      inverseJoinColumns={@ORM\JoinColumn(name="location_id", referencedColumnName="id")}
     *      )
     **/
    protected $hometown;
    
    /**
     * @ORM\ManyToMany(targetEntity="Location")
     * @ORM\JoinTable(name="current_location",
     *      joinColumns={@ORM\JoinColumn(name="person_id", referencedColumnName="id", unique=true)},
     *      inverseJoinColumns={@ORM\JoinColumn(name="location_id", referencedColumnName="id")}
     *      )
     **/
    protected $current;
    
    public function __construct() {
        $this->hometown = new \Doctrine\Common\Collections\ArrayCollection();
        $this->hometown = new \Doctrine\Common\Collections\ArrayCollection();
    }
    

    如果没有location 可以分配给hometowncurrent,那很好,不会占用任何空间。 当您确实有一个 location 可以分配给 hometowncurrent 时,它必须是来自 location 表的有效 location

    【讨论】:

    • 嗨@hcoat,感谢您的回复。在我的场景中,一个人只有一个家乡和一个当前位置,或者没有。所以,在我的情况下,Person <--> Location 应该是 1 <--> 0..1 对于这两种关系。因此,我将OneToOnenullable=true 建立关系。
    • 目前,Location 表没有指向任何表的任何链接,因为其他表(如 Person)使用 location_id 获取所需的信息,我不想向其中添加更多字段。虽然如果我使用 ManyToOne,它需要我这样做:( 有什么方法可以实现我的目标吗?
    • 你可能注意到了,我已经在没有教条的情况下实现了这个想法,现在我正在转向这个框架。我认为我提到的最好的数据库结构是我提到的。但是如果我想通过 Doctrine 来实现它,我需要以一种低效的方式来改变它。之前它只需要加入 2 个表,现在我必须加入 3 个。
    • 我的观点是,为什么可以为空的一对一关系需要创建唯一索引? CREATE UNIQUE INDEX UNIQ_8D93D6494341EE7D ON person (hometown_id);
    • 这意味着学说中的 1:1 关系不适用于多个 NULL 值。
    【解决方案2】:

    您似乎在寻找 FOREIGN KEY

    http://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html

    ALTER TABLE `Person` ADD INDEX ( `hometown_id` ) ;
    ALTER TABLE `Person` ADD FOREIGN KEY ( `hometown_id` ) REFERENCES `Location` ( `id` )
    ON DELETE RESTRICT ON UPDATE RESTRICT ;
    
    ALTER TABLE `Person` ADD INDEX ( `current_id` ) ;
    ALTER TABLE `Person` ADD FOREIGN KEY ( `current_id` ) REFERENCES `Location` ( `id` )
    ON DELETE RESTRICT ON UPDATE RESTRICT ;
    

    【讨论】:

    • “唯一”意味着你禁止两个人住在同一个城市
    • 感谢您的回复。 SQL 代码是由 Doctrine2 工具生成的,问题在于 PHP 而不是 MySQL 中的实体定义。
    猜你喜欢
    • 1970-01-01
    • 2020-06-09
    • 1970-01-01
    • 2017-02-28
    • 2021-12-15
    • 1970-01-01
    • 2014-08-13
    • 1970-01-01
    • 2013-02-02
    相关资源
    最近更新 更多