php - Doctrine multiple OneToMany/ManyToOne 双向完整性约束违反

标签 php orm doctrine-orm doctrine symfony-2.1

在 Symfony2 的最新 Doctrine 中,试图计算出两个对象之间的多重双向关系。

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

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)

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

这显然不是关于琐碎的 Person/Address 示例,而是更复杂的示例,但这是我在抽象方面的最佳尝试。

我确定我错过了一些明显的东西。谁能帮忙?

最佳答案

splinter 的关系定义

虽然从纯逻辑的角度来看您正在做的事情可能有意义,但从关系数据的角度来看却并非如此,尤其是从 Doctrine 的角度来看毫无意义。

Doctrine 试图维护 3 种不同的关系:

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

你看到问题了吗?

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

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

  • Address(拥有方)[双向] $person --Many:One--> $otherAddresses Person<

然后,向地址添加一个属性,该属性将该地址定义为主要。在 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.
}

使用两种不同的关系,但不要交叉

如果您保持从人到地址的单向一对一关系,问题就会自行解决。

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

不过你仍然会在这里遇到麻烦,因为如果出现以下情况,Doctrine 会报错: - 主要 (PostalAddress) 地址没有为 Many:One 定义的两边。 (因此您的“主要”地址也必须在 $otherAddresses 集合中)。 - 尝试删除或级联删除和更新将导致这两种关系发生冲突,即 Doctrine 关系约束的“交叉流”,因此您必须以编程方式处理这些操作。

关于php - Doctrine multiple OneToMany/ManyToOne 双向完整性约束违反,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16196334/

相关文章:

java - 使用 Hibernate EntityManager(与 Hibernate Core 相比)有什么缺点吗?

python - 从 php 过渡到 python/pylons/SQLAlchemy——ORM 现在是标准了吗?

php - Windows 和 Ubuntu 上印地语 Unicode 的打印问题

php - 将数据添加到表形式 sql 并存储回新数据库

php - 如何从 php 函数进行自动 javascript 函数调用?

php - Zend Acl - 模块、 Controller 、操作和模型

php - 具有多个实体管理器的 symfony 原则迁移

php - Kohana 验证 3.3

c# - 如何使用 EntityFramework 构建富领域模型

php - 使用 symfony 3 通过条令迁移执行下一个/上一个迁移