【问题标题】:It's possible to persist entities stored on session in Symfony2+Doctrine2?可以在 Symfony2+Doctrine2 中持久化存储在会话中的实体吗?
【发布时间】:2015-01-18 11:43:33
【问题描述】:

我正在我的项目中处理某种“复杂”表单,其中实体在每个步骤上都保持不变,因为单个表单在它们上被拆分。然后我有一个第一步(我们称之为 step1),我持久化一个实体并将其存储在会话中,请参见下面的代码:

$productoSolicitudEntity = new Entity\ProductoSolicitud();
$productoSolicitudForm = $this->createForm(new Form\ProductoSolicitudForm(), $productoSolicitudEntity);
$productoSolicitudForm->handleRequest($request);

if ($productoSolicitudForm->isValid()) {
    $productoSolicitudRequest = $request->get('productoSolicitud');

    try {
        $producto = $em->getRepository("AppBundle:Producto")->find($productoSolicitudRequest['producto']['nombre']);
        $productoSolicitudEntity->setProducto($producto);

        $condicionProducto = $em->getRepository("AppBundle:CondicionProducto")->find($productoSolicitudRequest['condicion_producto']);
        $productoSolicitudEntity->setCondicionProducto($condicionProducto);

        $finalidadProducto = $em->getRepository("AppBundle:FinalidadProducto")->find($productoSolicitudRequest['finalidad_producto']);
        $productoSolicitudEntity->setFinalidadProducto($finalidadProducto);

        $procedenciaProducto = $em->getRepository("AppBundle:ProcedenciaProducto")->find($productoSolicitudRequest['procedencia_producto']);
        $productoSolicitudEntity->setProcedenciaProducto($procedenciaProducto);

        $productoSolicitudEntity->setLote($productoSolicitudRequest['lote']);
        $solicitudUsuario = $em->getRepository("AppBundle:SolicitudUsuario")->find($session->get('solicitudUsuarioEntity')->getId());
        $productoSolicitudEntity->setSolicitudUsuario($solicitudUsuario);

        $em->persist($productoSolicitudEntity);
        $em->flush();

        $session->set('productoSolicitudEntity', $productoSolicitudEntity);
        $response['success'] = true;
    } catch (Exception $ex) {
        $status = 400;
        $response['error'] = $ex->getMessage();
    }
} else {
    $status = 400;
    $response['error'] = $this->get('translator')->trans('formularioNoValido');
    $response['formError'] = $this->getFormErrors($productoSolicitudForm);
}

然后在四个步骤中(我们称之为步骤 4)我需要将该实体附加到一个新实体,因为它们是相关的,这是涉及的代码:

$productoSolicitud = $session->get('productoSolicitudEntity');

if (! $productoSolicitud) {
    $status = 400;
    $response['error'] = 'No se encontró la solicitud';
}

$distribuidorEntity = new Entity\FabricanteDistribuidor();
$distribuidorForm = $this->createForm(new Form\DistribuidorForm(), $distribuidorEntity);

$distribuidorForm->handleRequest($request);

if ($distribuidorForm->isValid()) {
    $em->persist($distribuidorEntity);
    $em->flush();
    $session->set('distribuidorEntity', $distribuidorEntity);

    $distribuidorProductoSolicitudEntity = new Entity\DistribuidorProductoSolicitud();
    $distribuidorProductoSolicitudEntity->setProductoSolicitud($productoSolicitud);
    $distribuidorProductoSolicitudEntity->setFabricanteDistribuidor($distribuidorEntity);
    $em->persist($distribuidorProductoSolicitudEntity);
    $em->flush();
    $session->set('distribuidorEntity', $distribuidorEntity);
}

但我收到此错误:

通过关系“AppBundle\Entity\DistribuidorProductoSolicitud#producto_solicitud”找到了一个新实体,该实体未配置为对实体进行级联持久化操作: AppBundle\Entity\ProductoSolicitud@000000000a1f3e9d00007f88c54033f8。要解决这个问题:要么在这个未知实体上显式调用 EntityManager#persist() 要么配置级联在映射中持久保存此关联,例如 @ManyToOne(..,cascade={"persist"})。如果您无法找出导致问题的实体,请执行“AppBundle\Entity\ProductoSolicitud#__toString()”以获取线索。

由于冲突实体似乎是DistribuidorProductoSolicitud,因此我对其进行了更改:

/**
 * @ORM\ManyToOne(targetEntity="\AppBundle\Entity\ProductoSolicitud", cascade={"persist"})
 * @ORM\JoinColumn(name="producto_solicitud_id", referencedColumnName="id")
 */
protected $producto_solicitud;

但没有解决问题,有什么帮助吗?怎么了?我在这里缺少什么?我应该在ProductoSolicitud 实体处添加一个方法__toString(),但这应该返回什么?

这是涉及该问题的实体:

class DistribuidorProductoSolicitud
{
    use IdentifierAutogeneratedEntityTrait;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\FabricanteDistribuidor")
     * @ORM\JoinColumn(name="fabricante_distribuidor_id", referencedColumnName="id")
     */
    protected $fabricante_distribuidor;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\ProductoSolicitud", cascade={"persist"})
     * @ORM\JoinColumn(name="producto_solicitud_id", referencedColumnName="id")
     */
    protected $producto_solicitud;

    /**
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Pais", inversedBy="distribuidorProductoSolicitudPais", cascade={"persist"})
     * @ORM\JoinTable(name="nomencladores.pais_distribuidor_producto_solicitud", schema="nomencladores",
     *      joinColumns={@ORM\JoinColumn(name="distribuidor_producto_solicitud_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="pais_id", referencedColumnName="id")}
     * )
     */
    protected $paisesDistribuidorProductoSolicitudPais;
}


class ProductoSolicitud
{
    use IdentifierAutogeneratedEntityTrait;

    /**
     * @var \Producto
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Producto")
     * @ORM\JoinColumn(name="producto_id", referencedColumnName="id")
     */
    protected $producto;

    /**
     * @var \SolicitudUsuario
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\SolicitudUsuario", cascade={"persist"})
     * @ORM\JoinColumn(name="solicitud_usuario_id", referencedColumnName="id")
     */
    protected $solicitud_usuario;

    /**
     * @var \CondicionProducto
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\CondicionProducto")
     * @ORM\JoinColumn(name="condicion_producto_id", referencedColumnName="id")
     */
    protected $condicion_producto;

    /**
     * @var \FinalidadProducto
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\FinalidadProducto")
     * @ORM\JoinColumn(name="finalidad_producto_id", referencedColumnName="id")
     */
    protected $finalidad_producto;

    /**
     * @ORM\Column(name="lote", type="integer", nullable=false)
     */
    protected $lote;

    /**
     * @var \ProcedenciaProducto
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\ProcedenciaProducto")
     * @ORM\JoinColumn(name="procedencia_producto_id", referencedColumnName="id")
     */
    protected $procedencia_producto;
}

cascade={"persist"} 应该去哪里修复它?

我找到了this 的帖子,但它没有帮助。

【问题讨论】:

    标签: php symfony orm doctrine-orm


    【解决方案1】:

    尝试将cascade={"persist"} 添加到ManyToOne 的两侧(在ProductoSolicitudDistribuidorProductoSolicitud 中)。

    如果此ManyToOne 是单向的,请尝试将其更改为双向的OneToMany,并在两侧保持级联。

    ProductoSolicitud 类:

    /**
     * @OneToMany(targetEntity="AppBundle\Entity\DistribuidorProductoSolicitud", mappedBy="producto_solicitud", cascade={"persist"})
       @var \Doctrine\Common\Collections\ArrayCollection
     **/
     private $distribuidor_producto_solicidudes;
    

    在 DistribuidorProductoSolicidud 类中:

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\ProductoSolicitud", inversedBy="distribuidor_producto_solicidudes", cascade={"persist"})
     * @ORM\JoinColumn(name="producto_solicitud_id", referencedColumnName="id")
       @var \AppBundle\Entity\ProductoSolicidud
     */
     protected $producto_solicitud;
    

    【讨论】:

    • 好的,给我一点时间来编辑帖子并添加相关实体,因为我迷路了,不知道我应该在哪里添加cascade={"persist"}
    • 完成了,请看一下,如果可以的话,请用代码示例改进您的答案,提前感谢
    【解决方案2】:

    保存(或序列化)一个 Doctrine 实体 to the session is problematic (here's a relevant SO question/answer on the matter) - 因为它丢失了检测可在系统中识别的水合 Doctrine 对象所需的私有属性。

    由于缺少水合 Doctrine 对象的那些私有属性,它会将这些未水合对象视为全新的(以及其他相关对象)。

    您最好的解决方案是仅将对象标识符存储在会话中,稍后使用 find() 辅助函数检索它们。

    存储:

    $this->get('session')->set('objectId', $object->getId());
    

    稍后获取:

    $objectId = $this->get('session')->get('objectId');
    $object = $this->getDoctrine()->getRepository('AcmeBundle:Entity')->find($objectId);
    

    【讨论】:

    • “仅将对象标识符存储在会话中并稍后使用 find() 辅助函数检索它们”是什么意思?你能写一段代码来说明你的意思吗?我不知道该怎么做
    • 这是基本的东西 - 我已经添加了示例。确保替换为正确的实体名称。
    • 好的,好的,还有一个问题,我应该在设置之前删除会话吗?例如:$session->remove('solicitudUsuarioId'); $session->set('solicitudUsuarioId', $solicitudUsuarioEntity->getId()); 还是一直被覆盖?
    • @ReynierPM 它的行为就像一个普通的 PHP 数组 - 如果你每次都使用相同的键,它会覆盖 :)
    • 您可以使用引用代理代替 find (它不执行任何数据库查询)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-07
    • 2021-06-05
    • 1970-01-01
    • 2011-12-22
    • 2012-06-19
    • 2014-11-17
    • 1970-01-01
    相关资源
    最近更新 更多