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

Doctrine自动更新未修改User实体问题排查求助

问题原因及解决方案

问题原因

  • Doctrine的Unit of Work会自动跟踪所有托管实体(包括通过$this->getUser()获取的当前登录用户)的属性变化。
  • 你的User实体中,eraseCredentials()方法执行了unset($this->roles),这个操作直接销毁了对象的$roles属性。Doctrine检测到该属性从初始数组状态变为不存在,会判定为属性被修改。
  • 当调用$manager->flush()时,Doctrine会尝试更新这个被“篡改”的User实体,但此时$roles属性已被销毁,对应数据库字段的值为null,触发了roles字段非空的约束错误。
  • 注意:eraseCredentials()通常会在认证完成后被Symfony Security自动调用,导致User实体的属性被意外修改。

解决方案

方法1:修正eraseCredentials()方法的逻辑

eraseCredentials()的设计初衷是清除临时敏感凭证(比如明文密码),而非销毁Doctrine映射的持久化属性。修改User实体的该方法:

public function eraseCredentials()
{
    // 仅清除非持久化的敏感数据,比如临时存储的明文密码
    // 不要操作Doctrine映射的$roles、$password等持久化字段
    // 示例:如果有临时的plainPassword属性,只清除它
    // unset($this->plainPassword);
}

方法2:将User实体从Doctrine托管状态分离

如果需要保留原有eraseCredentials()逻辑,可以在获取用户后,将其从EntityManager的跟踪中移除,这样Doctrine就不会监控它的变化:

#[Route('/new', name: 'new', methods: ['POST'])]
public function order(
    Request $request,
    ServiceRepository $serviceRepository,
    EntityManagerInterface $manager
): JsonResponse
{
    $data = json_decode($request->getContent());

    if (!property_exists($data, 'service'))
        return $this->json(['status' => false, 'message' => 'service is required']);
    $service = $serviceRepository->find($data->service);

    $user = $this->getUser();
    $manager->detach($user); // 分离后Doctrine不再跟踪该实体

    $order = new Order();
    $order->setUser($user);
    $order->setCreatedAt(new \DateTimeImmutable());
    $order->setTotal(0);
    $order->setStatus(Order::STATUS_OPEN);
    $order->setService($service);

    $manager->persist($order);
    $manager->flush();

    return $this->json(['status' => true]);
}

方法3:重新获取未被修改的User实例

通过UserRepository重新查询用户,获取一个干净的、未被eraseCredentials()修改过的托管实例:

#[Route('/new', name: 'new', methods: ['POST'])]
public function order(
    Request $request,
    ServiceRepository $serviceRepository,
    UserRepository $userRepository,
    EntityManagerInterface $manager
): JsonResponse
{
    $data = json_decode($request->getContent());

    if (!property_exists($data, 'service'))
        return $this->json(['status' => false, 'message' => 'service is required']);
    $service = $serviceRepository->find($data->service);

    // 从仓库重新获取用户,避免使用被Security修改过的对象
    $user = $userRepository->find($this->getUser()->getId());

    $order = new Order();
    $order->setUser($user);
    $order->setCreatedAt(new \DateTimeImmutable());
    $order->setTotal(0);
    $order->setStatus(Order::STATUS_OPEN);
    $order->setService($service);

    $manager->persist($order);
    $manager->flush();

    return $this->json(['status' => true]);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 22:45:39