You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony5下Doctrine带额外字段多对多关联仅存最后一条数据如何解决

问题原因及修改方案

你只存最后一条关联数据是两个问题共同导致的,按以下步骤修改即可:

1. 修正控制器逻辑(最直接原因)

你把中间实体TemplateSection的实例化写在了循环外部,每次循环都修改同一个对象,之前的值会被覆盖,只有最后一次修改的内容会被保留。同时删除循环外多余的persist($templateSection)语句。

修改后控制器代码如下:

/**
 * @Route("/new", name="adminTemplateNew", methods={"GET","POST"})
 */
public function new(Request $request): Response
{
    $template = new Template();
    $form = $this->createForm(TemplateType::class, $template);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $entityManager = $this->getDoctrine()->getManager();
        $data = $form->getData();
        $repo = $entityManager->getRepository(Section::class);
        $template->setCreatedAt(new DateTime('NOW'));

        $sections = explode(',', $form->get('secInput')->getData());
        $count = 1;
        foreach ($sections as $secId) {
            if ( null !== $section = $repo->find($secId) ) {
                // 把实例化移到循环内部,每个关联对应一个独立的中间实体对象
                $templateSection = new TemplateSection();
                $templateSection->setSortOrder($count);
                $templateSection->setTemplate($template);
                $templateSection->setSection($section);
                $template->addSection($templateSection);
                $entityManager->persist($templateSection);
                $count++;
            }
        }

        // 删掉这里多余的persist($templateSection),循环内已经处理过所有中间实体
        $entityManager->persist($template);
        $entityManager->flush();

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

2. 修正实体关联映射配置(否则关联查询、级联操作会异常)

当前3个实体的关联注解配置全是错的,对应修改如下:

Template实体修正

$sections属性的mappedBy要指向中间实体TemplateSection里的template字段:

/**
 * @ORM\OneToMany(targetEntity=TemplateSection::class, mappedBy="template", cascade={"persist"})
 */
private $sections;

同时要确保你的构造方法和addSection方法写法正确:

public function __construct()
{
    $this->sections = new ArrayCollection();
}

public function addSection(TemplateSection $templateSection): self
{
    if (!$this->sections->contains($templateSection)) {
        $this->sections[] = $templateSection;
        $templateSection->setTemplate($this);
    }
    return $this;
}

Section实体修正

一个Section可以对应多个Template关联,属性名建议改为$templates,mappedBy指向中间实体的section字段:

/**
 * @ORM\OneToMany(targetEntity=TemplateSection::class, mappedBy="section")
 */
private $templates;

public function __construct()
{
    $this->templates = new ArrayCollection();
}

TemplateSection中间实体修正

两个ManyToOne的inversedBy要对应关联实体的关联属性名,不是id:

/**
 * @ORM\ManyToOne(targetEntity=Template::class, inversedBy="sections", cascade={"persist"})
 * @ORM\JoinColumn(nullable=false)
 */
private $template;

/**
 * @ORM\ManyToOne(targetEntity=Section::class, inversedBy="templates", cascade={"persist"})
 * @ORM\JoinColumn(nullable=false)
 */
private $section;

修改完之后执行php bin/console make:migration生成迁移更新数据库表结构,再测试提交即可正常存储所有关联数据。


内容的提问来源于stack exchange,提问作者JustMe69

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 20:54:03