Symfony持久化对象到数据库报错:期望integer/null,传入User对象
解决表单提交时的类型错误:Expected argument of type "integer or null", "App\Entity\User" given
这个错误的核心原因很明确:你的表单里guru_id字段用了EntityType组件,它默认会返回完整的User实体对象,但你的Tag实体中guru_id属性定义的是integer类型,两者类型不匹配,导致Symfony在绑定表单数据时抛出类型错误。
下面提供两种解决方案,推荐第一种(符合Doctrine最佳实践),第二种适合你暂时不想修改实体结构的场景:
方案一:建立Doctrine实体关联(推荐)
如果guru_id本来就代表关联的用户,直接用实体关联关系更规范,也能避免类型问题:
1. 更新Tag实体
把原来的guru_id属性替换为ManyToOne关联:
// src/Entity/Tag.php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use App\Entity\User; /** * @ORM\Entity(repositoryClass="App\Repository\TagRepository") */ class Tag { // ... 保留其他原有属性和方法 ... /** * @ORM\ManyToOne(targetEntity=User::class) * @ORM\JoinColumn(name="guru_id", referencedColumnName="id", nullable=true) */ private $guru; // 新增关联的getter和setter public function getGuru(): ?User { return $this->guru; } public function setGuru(?User $guru): self { $this->guru = $guru; return $this; } // 可选:保留getGuruId方法方便快速获取ID public function getGuruId(): ?int { return $this->guru ? $this->guru->getId() : null; } }
2. 更新AddType表单
将表单字段从guru_id改为对应关联属性guru:
// src/Form/Tag/AddType.php use App\Entity\Tag; use App\Entity\User; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; class AddType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('name', TextType::class) ->add('description', TextareaType::class) ->add('guru', EntityType::class, [ 'class' => User::class, 'choice_label' => 'username', 'required' => false // 允许不选择用户 ]); } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => Tag::class ]); } }
3. 简化控制器代码
表单会自动绑定关联对象,不需要手动处理ID:
// src/Controller/Tag/AddController.php public function add(Request $request) { $tag = new Tag(); $form = $this->createForm(AddType::class, $tag); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $entityManager = $this->getDoctrine()->getManager(); $tag->setApproved(false); $tag->setCreatedTs(new \DateTime()); try { $entityManager->persist($tag); $entityManager->flush(); $guruInfo = $tag->getGuru() ? $tag->getGuru()->getUsername() : 'no assigned guru'; $this->addFlash('success', "Tag Submitted for review! {$guruInfo}"); } catch (\Exception $e) { $this->addFlash('danger', 'Something went skew-if. Please try again.'); } return $this->redirectToRoute('tag_add'); } return $this->render('tag/add.html.twig', ['form' => $form->createView()]); }
方案二:仅存储用户ID(不推荐,但适配当前实体结构)
如果只想存ID而不建立关联,可以修改表单让它直接返回用户ID:
修改AddType为ChoiceType
把EntityType换成ChoiceType,指定返回值为用户ID:
// src/Form/Tag/AddType.php use App\Entity\User; use Doctrine\ORM\EntityRepository; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; // 记得让AddType继承AbstractController才能调用getDoctrine class AddType extends AbstractController { public function buildForm(FormBuilderInterface $builder, array $options) { $users = $this->getDoctrine()->getRepository(User::class)->findAll(); $builder->add('name', TextType::class) ->add('description', TextareaType::class) ->add('guru_id', ChoiceType::class, [ 'choices' => $users, 'choice_label' => 'username', 'choice_value' => 'id', // 明确返回用户ID而非对象 'required' => false ]); } // ... 保留configureOptions方法 ... }
这样表单提交后,$tag->getGuruId()会直接得到整数ID,不需要额外处理,你的原有控制器代码可以继续使用。
内容的提问来源于stack exchange,提问作者treyBake
相关产品推荐
相关产品推荐

