gpt4 book ai didi

php - 如何持久化自引用的 Doctrine 实体?

转载 作者:行者123 更新时间:2023-12-05 05:47:56 25 4
gpt4 key购买 nike

我有两个相互引用且没有空约束的实体,并尝试使用以下脚本来持久化它们:

$parentEntity = new \App\Entity\ParentEntity();
$childEntity = new \App\Entity\ChildEntity();
$childEntity->setParentEntity($parentEntity);
$parentEntity->setRootChildEntity($childEntity);

$this->entityManager->persist($parentEntity);
$this->entityManager->persist($childEntity);

printf('$parentEntity->getId(): %s'.PHP_EOL, $parentEntity->getId());
printf('$childEntity->getId(): %s'.PHP_EOL, $childEntity->getId());
printf('$parentEntity->getRootChildEntity()->getId(): %s'.PHP_EOL, $parentEntity->getRootChildEntity()->getId());
printf('$childEntity->getParentEntity()->getId(): %s'.PHP_EOL, $childEntity->getParentEntity()->getId());

$this->entityManager->flush();

执行脚本时,两个实体在持久化后都填充了整数 ID(通过 SELECT NEXTVAL 查询获得),但是在刷新时,使用 NULL 并且我得到了一个不为零的违规行为。

如果我只是得到一个外键约束,我会理解为什么,我可以通过使约束可延迟或通过暂时禁用触发器来绕过它们来绕过它。

但 null 违规情况并非如此。为什么会这样?在不删除我希望保留的非空约束的情况下,有没有办法绕过它?

doctrine.DEBUG: SELECT NEXTVAL('parent_entity_id_seq') [] []
doctrine.DEBUG: SELECT NEXTVAL('child_entity_id_seq') [] []

$parentEntity->getId(): 1
$childEntity->getId(): 1
$parentEntity->getRootChildEntity()->getId(): 1
$childEntity->getParentEntity()->getId(): 1

doctrine.DEBUG: "START TRANSACTION" [] []
doctrine.DEBUG: INSERT INTO parent_entity (id, root_child_entity_id) VALUES (?, ?) {"1":1,"2":null} []
doctrine.DEBUG: "ROLLBACK" [] []
console.CRITICAL: Error thrown while running command "app:add-tenant". Message: "An exception occurred while executing a query: SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column "root_child_entity_id" of relation "parent_entity" violates not-null constraint DETAIL: Failing row contains (1, null)." {"exception":"[object] (Doctrine\\DBAL\\Exception\\NotNullConstraintViolationException(code: 7): An exception occurred while executing a query: SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column \"root_child_entity_id\" of relation \"parent_entity\" violates not-null constraint\nDETAIL: Failing row contains (1, null). at /srv/api/vendor/doctrine/dbal/src/Driver/API/PostgreSQL/ExceptionConverter.php:51)\n[previous exception] [object] (Doctrine\\DBAL\\Driver\\PDO\\Exception(code: 7): SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column \"root_child_entity_id\" of relation \"parent_entity\" violates not-null constraint\nDETAIL: Failing row contains (1, null). at /srv/api/vendor/doctrine/dbal/src/Driver/PDO/Exception.php:26)\n[previous exception] [object] (PDOException(code: 23502): SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column \"root_child_entity_id\" of relation \"parent_entity\" violates not-null constraint\nDETAIL: Failing row contains (1, null). at /srv/api/vendor/doctrine/dbal/src/Driver/PDO/Statement.php:101)","command":"app:add-tenant","message":"An exception occurred while executing a query: SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column \"root_child_entity_id\" of relation \"parent_entity\" violates not-null constraint\nDETAIL: Failing row contains (1, null)."} []

我的实体:

<?php

namespace App\Entity;

use App\Repository\ParentEntityRepository;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class ParentEntity
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $id;

#[ORM\ManyToOne(targetEntity: ChildEntity::class)]
#[ORM\JoinColumn(nullable: false)]
private $rootChildEntity;

public function getId(): ?int
{
return $this->id;
}

public function getRootChildEntity(): ?ChildEntity
{
return $this->rootChildEntity;
}

public function setRootChildEntity(?ChildEntity $rootChildEntity): self
{
$this->rootChildEntity = $rootChildEntity;

return $this;
}
}
<?php

namespace App\Entity;

use App\Repository\ChildEntityRepository;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class ChildEntity
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $id;

#[ORM\ManyToOne(targetEntity: ParentEntity::class)]
#[ORM\JoinColumn(nullable: false)]
private $parentEntity;

public function getId(): ?int
{
return $this->id;
}

public function getParentEntity(): ?ParentEntity
{
return $this->parentEntity;
}

public function setParentEntity(?ParentEntity $parentEntity): self
{
$this->parentEntity = $parentEntity;

return $this;
}
}

生成以下 SQL:

doctrine.DEBUG: CREATE SEQUENCE child_entity_id_seq INCREMENT BY 1 MINVALUE 1 START 1 [] []
doctrine.DEBUG: CREATE SEQUENCE parent_entity_id_seq INCREMENT BY 1 MINVALUE 1 START 1 [] []
doctrine.DEBUG: CREATE TABLE child_entity (id INT NOT NULL, parent_entity_id INT NOT NULL, PRIMARY KEY(id)) [] []
doctrine.DEBUG: CREATE INDEX IDX_677D8034706E52B3 ON child_entity (parent_entity_id) [] []
doctrine.DEBUG: CREATE TABLE parent_entity (id INT NOT NULL, root_child_entity_id INT NOT NULL, PRIMARY KEY(id)) [] []
doctrine.DEBUG: CREATE INDEX IDX_413B87AEE5B68E27 ON parent_entity (root_child_entity_id) [] []
doctrine.DEBUG: ALTER TABLE child_entity ADD CONSTRAINT FK_677D8034706E52B3 FOREIGN KEY (parent_entity_id) REFERENCES parent_entity (id) NOT DEFERRABLE INITIALLY IMMEDIATE [] []
doctrine.DEBUG: ALTER TABLE parent_entity ADD CONSTRAINT FK_413B87AEE5B68E27 FOREIGN KEY (root_child_entity_id) REFERENCES child_entity (id) NOT DEFERRABLE INITIALLY IMMEDIATE [] []

最佳答案

当强制执行即时一致性时,所有 ID 都定义为不可为 null 的循环实体不可能按顺序持续存在。这是几乎每个数据库供应商的默认设置。

因此,首先您需要推迟一致性 - 参见 http://dbadailystuff.com/deferred-constraints-in-postgresql .具体对于 PostgreSQL 和 Doctrine ORM,您可以通过为外键指定 deferrable 选项来解决这个问题,请参阅 https://github.com/doctrine/dbal/blob/e839cecc812fd04ec6c39fc865302b6a322d967d/src/Platforms/PostgreSQLPlatform.php#L439 .

其次,您需要说服 Doctrine ORM 插入带有子行 ID 的父行。我怀疑是否有直接支持,因为第一点在数据库供应商之间非常不一致,但请随时在 https://github.com/doctrine/orm/issues 开票,作者可能会建议您至少如何强制 Doctrine ORM 立即插入子 ID。

关于php - 如何持久化自引用的 Doctrine 实体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70908713/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com