修改前如何获取原始数据?

How to get original data before modifying?

我对产品实体有简单的 editAction。它以原始的标准方式运行良好,但在编辑后保留 Product 之前我需要一些特殊的验证。产品在不同领域的价格很少。在项目中,我对产品进行了常规设置 "minimal price"。在编辑后保存产品之前,我想将价格与 "minimal price" 进行比较。我是这样做的:

public function editAction(Request $request, Product $pr1, UserInterface $op)
{
    // 1
    $pr_original = $this->getDoctrine()->getRepository(Product::class)->getProductById($pr1->getId());

    $form = $this->createForm('AppBundle\Form\ProductType', $product);
    $form->handleRequest($request); 

    if($form->isSubmitted() && $form->isValid())
    {
        // 2
        $em = $this->getDoctrine()->getManager();
        $em->persist($product);
        $em->flush();
    }

    return $this->redirect(path('product_list'));
}

在 2 中有一个地方我正在比较值。但问题是......我无法获得原始值进行比较。在 1 中,我想获得原始产品,但它会 $pr_original 具有已经更改的值!这很奇怪,因为我直接在数据库中看到该对象仍然具有原始值。所以我认为 Symfony 不会对数据库进行新查询。那么现在怎么办?如何让 Symfony 获取原始对象?

感谢@Cerad - 你的评论是解决方案:

Doctrine 具有所谓的工作缓存单元。每次您使用相同的 ID 查询时,您总是会返回完全相同的对象。考虑克隆您的实体:

$prOriginal = clone $pr1;

它对我来说效果很好。

您需要了解 Doctrine 为您做了什么。 ORM 不是易于查询的创建者。它们将您的数据库状态映射到您的代码可以理解并能够使用的内存对象。

因此,当您像以前一样传递表单时,学说会查询对象并更新对象状态中的值。因此,在处理表单之后,您的对象已经具有与数据库中不同的状态。学说唯一要做的就是坚持和刷新,或者换句话说,注册状态更改将反映在数据库中(坚持)并实际更改数据库值(刷新)。

如果您查询的对象是 "managed"(意思是,该对象已经被查询过并且在 doctrine 的内存中),那么为了提高效率,doctrine 将为您提供内存中的对象。它不会再次查询数据库。您可以在管理器中调用 refresh method 以从数据库更新对象的状态,但这将意味着丢失尚未持久化的状态,例如来自您的表单的数据。

在这种情况下,我建议的是创建一个表单事件,将用户写入的值与您的系统值进行比较。表单事件必须是 preSetData,因为您想在使用新数据更新实体之前进行比较。您可以在此处查看更多内容 here

另一种方法是创建自定义验证约束。如果您的系统值是固定的,您可以使用自定义验证器对其进行验证。或者甚至,使用正常的 Comparison Constraints.

希望此信息对您有所帮助!