首页 > 解决方案 > Symfony - 创建新实体而不是更新现有实体

问题描述

我有以下结构:

包含指向属性及其值的链接的类别属性:

<?php


class CategoryProperty
{

// ...

/**
 * @var Property
 *
 * @ORM\ManyToOne(targetEntity="App\Entity\Property")
 * @ORM\JoinColumn(onDelete="cascade", nullable=false)
 */
private $property;

/**
 * Набор значений свойства доступных в product builder, null если любое значение.
 *
 * @var PropertyValueEntry
 * @Assert\Valid
 *
 * @ORM\OneToOne(targetEntity="App\Entity\Properties\PropertyValues\PropertyValueEntry",
 * cascade={"persist", "remove"})
 */
private $propertyValue;

// ...

}

带有鉴别器映射的抽象属性值类型:

<?php

/**
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="type", type="integer")
 * @ORM\DiscriminatorMap({
 *     "1": "StringValue",
 *     "2": "IntegerValue",
 *     "3": "BooleanValue",
 *     "4": "TextValue",
 *     "6": "EnumValue",
 *     "7": "SetValue",
 *     "9": "LengthValue",
 *     "10": "AreaValue",
 *     "11": "VolumeValue",
 *     "12": "MassValue",
 * })
 * @ORM\Table(name="properties_values__value_entry")
 */
abstract class PropertyValueEntry
{
    /**
     * @var Property
     *
     * @ORM\ManyToOne(targetEntity="App\Entity\Property")
     */
    private $property;

    public function __construct(Property $property)
    {
        $this->property = $property;
    }

    public function getProperty(): Property
    {
        return $this->property;
    }

    /**
     * @return mixed
     */
    abstract public function getValue();

    /**
     * @param mixed $value
     */
    abstract public function setValue($value): void;
}

以及一个示例具体值类型:

<?php

/**
 * @ORM\Entity
 * @ORM\Table(name="properties_values__integer_value")
 */
class IntegerValue extends PropertyValueEntry
{
    /**
     * @var int
     * @Assert\NotNull
     *
     * @ORM\Column(type="integer")
     */
    private $value = 0;

    public function getValue(): int
    {
        return $this->value;
    }

    /**
     * @param int|null $value
     */
    public function setValue($value): void
    {
        if (!\is_int($value)) {
            throw new InvalidArgumentException('BooleanValue accepts integer values only');
        }
        $this->value = $value;
    }
}

由于某种原因,提交表单时,不会更新 IntegerValue 的值,而是创建一个新实体,并在 properties_values__value_entry / properties_values__integer_value 中创建新行。我尝试通过 $this->em->persist($entity) 进行跟踪,其中 $entity 是 CategoryProperty,并且似乎 IntegerValue 被标记为脏并重新创建。如何跟踪发生这种情况的原因?我的表单处理非常标准:

<?php

public function editAction(): Response
{
    $id = $this->request->query->get('id');
    $easyadmin = $this->request->attributes->get('easyadmin');
    $entity = $easyadmin['item'];

    $isReload = 'reload' === $this->request->request->get('action');
    $editForm = $this->createForm(CategoryPropertyType::class, $entity, [
        'category' => $this->getCatalog(),
        'is_reload' => $isReload,
    ]);
    $deleteForm = $this->createDeleteForm($this->entity['name'], $id);

    $editForm->handleRequest($this->request);
    if ($editForm->isSubmitted() && $editForm->isValid()) {
        if (!$isReload) {
            $this->em->persist($entity);
            $this->em->flush();

            return $this->redirectToReferrer();
        }
    }

    return $this->render($this->entity['templates']['edit'], [
        'form' => $editForm->createView(),
        'entity' => $entity,
        'delete_form' => $deleteForm->createView(),
    ]);
}

更新 #1 我已经尝试过的:通过 ID 从实体管理器中检索类别属性

$entity = $this->em->find(CategoryProperty::class, $id);

总而言之,这似乎与我根据选择创建了一个动态表单这一事实有关。当我添加一个类别属性时,我会显示一个带有属性类型列表(整数、字符串、面积、体积等)的下拉列表,并在选择后显示该属性的新表单。尽管这可以正常工作并且可以毫无问题地添加新属性,但似乎编辑相同属性的代码缺少某些内容,而不是更新它重新创建它。

标签: phpsymfonyorm

解决方案


可能性#1:直接从实体管理器加载实体

您似乎根本没有检索要修改的现有实体。

$entity = $easyadmin['item'];

这不应该使用 Doctrine 来检索现有实体吗?例如:

if (!($entity = $this->getRepository(CategoryProperty::class)->findOneById($id))) {
    throw $this->createNotFoundException("Category property not found.");
}

半相关:您可能还想检查是否指定了整数 ID,这$id = $this->request->query->get('id');是非常假设的:

if (intval($id = $this->request->query->get('id')) < 1) {
    throw $this->createNotFoundException("Category property not specified.");
}

可能性 2:缺少具有一对一关系的标识符引用

我认为您可能会得到重复,因为CategoryProperty不保留对 a 的任何引用PropertyValueEntry

/**
 * Набор значений свойства доступных в product builder, null если любое значение.
 *
 * @var PropertyValueEntry
 * @Assert\Valid
 *
 * @ORM\OneToOne(targetEntity="App\Entity\Properties\PropertyValues\PropertyValueEntry", cascade={"persist", "remove"})
 */
private $propertyValue;

但是PropertyValueEntry与 没有反比关系CategoryProperty

单向的一对一是可以的,但它必须有一个@ORM\JoinColumn指令来确保外来的标识符PropertyValueEntry是持久的。否则,编辑表单将没有任何信息来知道PropertyValueEntry它需要编辑哪个现有(或派生)。这就是为什么您的“properties_values__value_entry”表单字段被重置为PropertyValueEntry在提交表单时创建的新实例(或派生实例)。

您尚未显示实体类的来源,Property因此我无法检查您的实体关系中是否存在任何进一步的问题。


推荐阅读