如何让 Doctrine cascade 持久工作?

How to get the Doctrine cascade persisting working?

我正在使用 Doctrine v2.4.2 开发 ZF2/Apigility 应用程序。

模型结构如下所示:anAssethasanAttachment(所以,这是一个1:1关系):

问题是我无法坚持带有嵌入式 AttachmentAsset 并得到错误

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默认nullabletrue 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;
}