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
相关产品推荐
相关产品推荐

