Symfony5.2同EntityType不同choice_value多表单报错问题
问题根因
这个报错是Symfony 5.2版本的已知特性缺陷导致:
- 同一请求生命周期内,
EntityType默认会共享AbstractChoiceLoader的全局缓存,减少重复查询数据库的性能损耗 - 5.2及更早版本的缓存key生成逻辑未将
choice_value配置项纳入计算,导致绑定同一个Foo::class、但choice_value不同的两个表单会复用同一份选项映射缓存 - 第一个表单的缓存是
code字段值到Foo实体的映射,第二个表单提交的是id值,在旧缓存中匹配不到对应选项,就会抛出对应错误。
解决方案
方案1:临时清空表单全局缓存(最便捷)
在调用forward转发请求前,手动清空表单工厂的全局缓存即可,修改转发代码如下:
// 清空表单缓存,避免前序表单的选项缓存影响后续表单创建 $this->get('form.factory')->clearCache(); $response = $this->forward('App\Controller\OrderController::create', [ 'request' => $request->duplicate(null, $refactorPayload) ]);
方案2:为第二个表单配置独立的选项加载器
如果不想影响全局缓存,可以给第二个表单的EntityType单独配置独立的choice_loader,不走共享缓存:
首先引入依赖类:
use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader; use Symfony\Component\OptionsResolver\Options;
然后修改目标FormType中Foo字段的配置:
->add('foo', EntityType::class, [ 'class' => Foo::class, 'choice_value' => 'id', 'choice_loader' => function (Options $options) { $repo = $this->entityManager->getRepository(Foo::class); return new CallbackChoiceLoader( // 加载所有选项的回调 fn() => $repo->findAll(), // 单个值转实体的回调 fn($value) => $repo->find($value), // 批量值转实体的回调 fn(array $values) => $repo->findBy(['id' => $values]) ); } ])
方案3:升级Symfony版本
该缓存key的缺陷已经在Symfony 5.3及之后版本修复,如果允许版本升级,直接升级到5.4 LTS版本即可从根本上解决该问题,无需额外修改业务代码。
内容的提问来源于stack exchange,提问作者Vodkhard
相关产品推荐
相关产品推荐

