如何让 Doctrine cascade 持久工作?
How to get the Doctrine cascade persisting working?
我正在使用 Doctrine v2.4.2
开发 ZF2/Apigility 应用程序。
模型结构如下所示:an
Asset
has
an
Attachment
(所以,这是一个1:1
关系):
问题是我无法坚持带有嵌入式 Attachment
的 Asset
并得到错误
23000, 1048, Column 'attachment_linkassetuuid' cannot be null
似乎 Doctrine 试图先保存 Attachment
,找不到列 attachment_linkassetuuid
的值,将其设置为 null
,并且外键约束被破坏。
如何正确定义实体并让级联持续工作?
Asset
namespace MyDoctrineDataAccess\Model\Entity;
...
/**
* Asset
*
* @ORM\Table(name="tbl_asset")
* @ORM\Entity
*/
class Asset
{
/**
* @var string @ORM\Column(name="asset_uuid", type="string", length=36, nullable=false)
* @ORM\Id
*/
private $uuid;
/**
* @var \MyDoctrineDataAccess\Model\Entity\Attachment
* @ORM\OneToOne(targetEntity="MyDoctrineDataAccess\Model\Entity\Attachment", mappedBy="asset", cascade={"remove", "persist"}, orphanRemoval=true)
*/
private $attachment;
...
}
/**
* @param \MyDoctrineDataAccess\Model\Entity\Attachment $attachment
*/
public function setAttachment($attachment) {
$this->attachment = $attachment;
return $this;
}
/**
* @return the $attachment
*/
public function getAttachment() {
return $this->attachment;
}
Attachment
namespace MyDoctrineDataAccess\Model\Entity;
...
/**
* Attachment
*
* @ORM\Table(name="tbl_attachment", indexes={@ORM\Index(name="fk_attachment_uuid", columns={"attachment_linkassetuuid"})})
* @ORM\Entity
*/
class Attachment
{
/**
*
* @var string @ORM\Column(name="attachment_uuid", type="string", length=36, nullable=false)
* @ORM\Id
*/
private $uuid;
/**
*
* @var \MyDoctrineDataAccess\Model\Entity\Asset
* @ORM\OneToOne(targetEntity="\MyDoctrineDataAccess\Model\Entity\Asset", inversedBy="attachment", cascade={"persist"})
* @ORM\JoinColumn(name="attachment_linkassetuuid", referencedColumnName="asset_uuid")
*/
private $asset;
...
}
/**
*
* @param \MyDoctrineDataAccess\Model\Entity\Asset $asset
*/
public function setAsset($asset)
{
$this->asset = $asset;
return $this;
}
/**
*
* @return the $asset
*
*/
public function getAsset()
{
return $this->asset;
}
AssetService
namespace MyApi\V1\Rest\Asset;
...
class AssetService implements ServiceManagerAwareInterface
{
...
public function saveAssets($data)
{
$entityManager = $this->serviceManager->get('Doctrine\ORM\EntityManager');
$assetRepository = $entityManager->getRepository('My\Model\Entity\Asset');
$hydratorManager = $this->serviceManager->get('hydratormanager');
$hydrator = $hydratorManager->get('My\Model\Entity\Hydrator\EntityHydrator');
foreach ($data as $assetData) {
$asset = new Asset();
$hydrator->hydrate($assetData, $asset);
$entityManager->persist($asset);
$entityManager->flush();
}
}
...
}
因为@JoinColumn
默认nullable
到true
according to the Doctrine documentation我不太明白这个错误。但我确实看到,在您的 Attachment
实体 @table
定义中,您声明了一个索引:
indexes={@ORM\Index(name="fk_attachment_uuid", columns={"attachment_linkassetuuid"})}
尝试一次删除它,重建你的数据库并检查它是否解决了你的问题。如果没有,请发表评论,我会再看看。
勾选the OneToOne
example in the Doctrine documentation。那里没有提到像您一样添加 @index
。 Doctrine 会自动将必要的索引添加到你的关系列中。
更新:
我认为问题可能出在 Asset
不是关系的拥有方。查看文档 here。尝试像这样更改 setAttachment
方法:
public function setAttachment($attachment)
{
$this->attachment = $attachment;
$attachment->setAsset($this);
return $this;
}
我正在使用 Doctrine v2.4.2
开发 ZF2/Apigility 应用程序。
模型结构如下所示:an
Asset
has
an
Attachment
(所以,这是一个1:1
关系):
问题是我无法坚持带有嵌入式 Attachment
的 Asset
并得到错误
23000, 1048, Column 'attachment_linkassetuuid' cannot be null
似乎 Doctrine 试图先保存 Attachment
,找不到列 attachment_linkassetuuid
的值,将其设置为 null
,并且外键约束被破坏。
如何正确定义实体并让级联持续工作?
Asset
namespace MyDoctrineDataAccess\Model\Entity;
...
/**
* Asset
*
* @ORM\Table(name="tbl_asset")
* @ORM\Entity
*/
class Asset
{
/**
* @var string @ORM\Column(name="asset_uuid", type="string", length=36, nullable=false)
* @ORM\Id
*/
private $uuid;
/**
* @var \MyDoctrineDataAccess\Model\Entity\Attachment
* @ORM\OneToOne(targetEntity="MyDoctrineDataAccess\Model\Entity\Attachment", mappedBy="asset", cascade={"remove", "persist"}, orphanRemoval=true)
*/
private $attachment;
...
}
/**
* @param \MyDoctrineDataAccess\Model\Entity\Attachment $attachment
*/
public function setAttachment($attachment) {
$this->attachment = $attachment;
return $this;
}
/**
* @return the $attachment
*/
public function getAttachment() {
return $this->attachment;
}
Attachment
namespace MyDoctrineDataAccess\Model\Entity;
...
/**
* Attachment
*
* @ORM\Table(name="tbl_attachment", indexes={@ORM\Index(name="fk_attachment_uuid", columns={"attachment_linkassetuuid"})})
* @ORM\Entity
*/
class Attachment
{
/**
*
* @var string @ORM\Column(name="attachment_uuid", type="string", length=36, nullable=false)
* @ORM\Id
*/
private $uuid;
/**
*
* @var \MyDoctrineDataAccess\Model\Entity\Asset
* @ORM\OneToOne(targetEntity="\MyDoctrineDataAccess\Model\Entity\Asset", inversedBy="attachment", cascade={"persist"})
* @ORM\JoinColumn(name="attachment_linkassetuuid", referencedColumnName="asset_uuid")
*/
private $asset;
...
}
/**
*
* @param \MyDoctrineDataAccess\Model\Entity\Asset $asset
*/
public function setAsset($asset)
{
$this->asset = $asset;
return $this;
}
/**
*
* @return the $asset
*
*/
public function getAsset()
{
return $this->asset;
}
AssetService
namespace MyApi\V1\Rest\Asset;
...
class AssetService implements ServiceManagerAwareInterface
{
...
public function saveAssets($data)
{
$entityManager = $this->serviceManager->get('Doctrine\ORM\EntityManager');
$assetRepository = $entityManager->getRepository('My\Model\Entity\Asset');
$hydratorManager = $this->serviceManager->get('hydratormanager');
$hydrator = $hydratorManager->get('My\Model\Entity\Hydrator\EntityHydrator');
foreach ($data as $assetData) {
$asset = new Asset();
$hydrator->hydrate($assetData, $asset);
$entityManager->persist($asset);
$entityManager->flush();
}
}
...
}
因为@JoinColumn
默认nullable
到true
according to the Doctrine documentation我不太明白这个错误。但我确实看到,在您的 Attachment
实体 @table
定义中,您声明了一个索引:
indexes={@ORM\Index(name="fk_attachment_uuid", columns={"attachment_linkassetuuid"})}
尝试一次删除它,重建你的数据库并检查它是否解决了你的问题。如果没有,请发表评论,我会再看看。
勾选the OneToOne
example in the Doctrine documentation。那里没有提到像您一样添加 @index
。 Doctrine 会自动将必要的索引添加到你的关系列中。
更新:
我认为问题可能出在 Asset
不是关系的拥有方。查看文档 here。尝试像这样更改 setAttachment
方法:
public function setAttachment($attachment)
{
$this->attachment = $attachment;
$attachment->setAsset($this);
return $this;
}