Doctrine多个OneToMany / ManyToOne双向完整性约束违规

时间:2013-04-24 15:41:14

标签: php orm doctrine-orm doctrine symfony-2.1

最新的Sytrfony2上的Doctrine试图找出两个对象之间的多个双向关系。

Person owner对象有一个邮政地址,然后是一个集合中的多个辅助地址,我删除了()Person,我希望它的所有地址也被删除(但删除一个地址不应该删除一个Person),但是我收到了这个错误 -

An exception occurred while executing 'DELETE FROM address WHERE id = ?' with
params {"1":"fb5e47de-2651-4069-b85e-8dbcbe8a6c4a"}:

[PDOException] SQLSTATE[23000]: Integrity constraint violation: 1451
Cannot delete or update a parent row: a foreign key constraint fails
(`db`.`address`, CONSTRAINT `FK_633704 C29C1004E`
FOREIGN KEY (`person_id`) REFERENCES `person` (`id`))

class Person
{

    /**
     * @var Address postalAddress
     *
     * @ORM\OneToOne(targetEntity="Address", cascade={"all"}, orphanRemoval=true)
     * @ORM\JoinColumn(onDelete="cascade")
     */
    private $postalAddress;

    /**
     * @var \Doctrine\Common\Collections\Collection otherAddresses
     *
     * @ORM\OneToMany(targetEntity="Address", mappedBy="person", cascade={"all"}, orphanRemoval=true)
     */
    private $otherAddresses;


}

class Address
{

    /**
     * @var Person person
     *
     * @ORM\ManyToOne(targetEntity="Person", inversedBy="postalAddress, otherAddresses")
     * @ORM\JoinColumn(nullable=false)
     */
    private $person;
}

我认为可能是因为

inversedBy="postalAddress, otherAddresses"

我认为不支持多个inversedBy;然后我也试着改变

@ORM\JoinColumn(nullable=false)

可以为空,但我仍然得到错误。

这显然不是关于琐碎的人/地址示例,而是更复杂的事情,但这是我最好的抽象尝试。

我确信我错过了一些明显的东西。有人可以帮忙吗?

1 个答案:

答案 0 :(得分:2)

破坏的关系定义

虽然你所做的事情从纯粹的逻辑观点来看可能是有道理的,但它不是从关系数据的角度来看,而且从Doctrine的角度来看尤其没有意义。

学说正在努力维持三种不同的关系:

  • 地址(拥有方)[双向] $ person --Many:One--> $ otherAddresses
  • 地址(拥有方)[双向] $ person --Many:One--> $ postalAddress
  • (拥有方)[单向] $ postalAddress --One:One--> $ id 地址

你看到了问题吗?

使用关系标准来解决此问题。

这里的简单解决方案是使用为集合设置主要的非常常见的设计模式。从本质上讲,你只需要一种关系:

  • 地址(拥有方)[双向] $ person --Many:One--> $ otherAddresses

然后,添加以寻址一个属性,该属性将该地址定义为 primary 。在Person和Address实体中以编程方式处理:

Class Person
{
    . . .
    public function getPrimaryAddress() {
        if (null === $this->primaryAddress) {
            foreach($this->getOtherAddresses() as $address) {
                if ($address->isPrimary()) {
                    $this->primaryAddress = $address;
                    break;
                }
            }
        }

        return $this->primaryAddress;
    }

    // similar for the setter, update the old address as not primary if there is one, set the new one as primary.
}

使用两种不同的关系,但不跨越流

如果你将人与地之间的一对一关系保持一致,问题就解决了。

  • 地址(拥有方)[双向] $ person --Many:One--> $ otherAddresses
  • (拥有方)[单向] $ postalAddress --One:One--> 地址

但你仍然会遇到麻烦,因为如果出现以下情况,学说会抱怨:   - 主要( PostalAddress )地址没有定义 Many:One 的双方。 (所以你的“主要”地址也必须在$otherAddresses集合中)。   - 尝试删除或级联删除和更新将导致这两个关系冲突,“交叉流”的学说的关系约束,所以你必须以编程方式处理这些操作。