Symfony 5:当从 MappedBy Side 添加时,ManyToMany 关系不持久,没有 'by_reference' => false

Symfony 5: ManyToMany Relationship Not Persisting When Added from MappedBy Side Without 'by_reference' => false

提问人:Meyo GIT 提问时间:11/13/2023 最后编辑:Meyo GIT 更新时间:11/14/2023 访问量:25

问:

上下文:

我正在开发一个 Symfony 5 应用程序,其中实体 InventaireActif TypeActif 具有 ManyToMany 关系。通过Symfony表单管理这种关系时会出现一个问题。

问题:

在我的 TypeActif 表单中,当我添加 InventaireActif 实体时,除非我在表单生成器中设置了 'by_reference' => false 选项,否则它们不会持久化到数据库中。我想在不依赖此选项的情况下实现正确的行为。

实体配置:

发明Actif.php:

/**
 * @ORM\ManyToMany(targetEntity=TypeActif::class, inversedBy="lesActifs")
 */
private $lesTypesActifs;

public function __construct()
{
    $this->lesTypesActifs = new ArrayCollection();
    // ... other initializations ...
}

/**
 * @return Collection<int, TypeActif>
*/
public function getLesTypesActifs(): Collection
    {
        return $this->lesTypesActifs;
    }

    public function addLesTypesActif(TypeActif $lesTypesActif): self
    {
        if (!$this->lesTypesActifs->contains($lesTypesActif)) {
            $this->lesTypesActifs[] = $lesTypesActif;
        }

        return $this;
    }

    public function removeLesTypesActif(TypeActif $lesTypesActif): self
    {
        $this->lesTypesActifs->removeElement($lesTypesActif);

        return $this;
    }

TypeActif.php:

/**
 * @ORM\ManyToMany(targetEntity=InventaireActif::class, mappedBy="lesTypesActifs")
 */
private $lesActifs;

public function __construct()
{
    $this->lesActifs = new ArrayCollection();
    // ... other initializations ...
}

public function getLesActifs(): Collection
{
    return $this->lesActifs;
}

public function addLesActif(InventaireActif $lesActif): self
{
    if (!$this->lesActifs->contains($lesActif)) {
        $this->lesActifs[] = $lesActif;
        $lesActif->addLesTypesActif($this);
    }
    return $this;
}

public function removeLesActif(InventaireActif $lesActif): self
{
    if ($this->lesActifs->removeElement($lesActif)) {
        $lesActif->removeLesTypesActif($this);
    }
    return $this;
}

TypeActifType.php 中的表单配置:

public function buildForm(FormBuilderInterface $builder, array $options): void
{
    $builder
        // ... other fields ...
        ->add('lesActifs', EntityType::class, [
            'required' => false,
            'class' => InventaireActif::class,
            'choice_label' => 'libelle',
            // 'by_reference' => false,
            'multiple' => true,
            'query_builder' => function (InventaireActifRepository $repo) {
                return $repo->lesActifsReformesSortedASC();
            },
        ]);
}

在 TypeActifController.php 中编辑路由:

public function new(Request $request, TypeActifRepository $typeActifRepository, EntityManagerInterface $entityManager): Response
    {
        $typeActif = new TypeActif();
        $form = $this->createForm(TypeActifType::class, $typeActif);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $typeActifRepository->add($typeActif, true);

            return $this->redirectToRoute('app_type_actif_index', [], Response::HTTP_SEE_OTHER);
        }

        return $this->renderForm('type_actif/new.html.twig', [
            'type_actif' => $typeActif,
            'form' => $form,
        ]);
    }

“by_reference”问题:

  • 'by_reference' => false 未注释时,表单将完美运行,并且 ManyToMany 关系将按预期更新。

  • 但是,我想避免使用“by_reference”=> false。如果没有此选项,则通过 TypeActif 窗体添加 InventaireActif 实体不会保留更改。

尝试解决:

  • 确保两个实体中的添加删除方法同步。

  • 审查了学说配置和注释。

预期行为:

当通过 TypeActif 表单添加 InventaireActif 实体时,应将更改保存到数据库中,而无需将 'by_reference' => false 设置为 false。

当前行为:

如果没有 'by_reference' => false,则不会保留更改。不显示任何错误,日志也未显示任何异常情况。

表单 关系 symfony5 mappedby

评论


答:

0赞 Marleen 11/14/2023 #1

如果设置为(或省略),则 Symfony 的表单系统只需使用类的方法将选定的实体添加到指定的属性中。如果设置为 ,则改用您指定的自定义添加/删除方法。by_referencetrueArrayCollectionby_referencefalse

将实体保存到数据库时,仅保存对 ManyToMany 关系的拥有方所做的更改。代码中的拥有方是类中的属性。$lesTypesActifsInventaireActif

在您的表单中,如果没有 ,您只会更新实体的属性,这是关系的面,因此这就是不保存更改的原因。但是,如果添加 ,自定义添加/删除方法可确保拥有方也已更新,因此会保存更改。by_reference = false$lesActifsTypeActifby_reference = false

我不确定您是否也有一个通过修改其属性来更新实体的表单,但如果您没有,您可能只需切换实体的拥有面和反向面即可摆脱:InventaireActif$lesTypeActifby_reference = false

class TypeActif {
    /**
     * @ORM\ManyToMany(targetEntity=InventaireActif::class, inversedBy="lesTypesActifs")
     */
    private $lesActifs;

    ...
}

class InventaireActif {
    /**
     * @ORM\ManyToMany(targetEntity=TypeActif::class, mappedBy="lesActifs")
     */
    private $lesTypesActifs;

    ...
}

评论

0赞 Meyo GIT 11/16/2023
我不确定我是否理解,因为如果我反转两个实体的“mappedBy”和“inversedBy”,问题就会被颠倒过来,即如果我从“InventaireActif”表单修改“lesTypesActifs”,它不再起作用,不再考虑更改。但现在我可以删除 TypeActif.php 表单中的“by_reference => false”。
0赞 Marleen 11/16/2023
如果你也有一个形式,那么你就不能通过交换拥有面和反面来解决问题。在这种情况下,您必须继续使用 ,至少在其中一种形式中。InventaireActifby_reference