Zend+Doctrine2:如何使用 ArrayCollections() 正确刷新实体?

Posted

技术标签:

【中文标题】Zend+Doctrine2:如何使用 ArrayCollections() 正确刷新实体?【英文标题】:Zend+Doctrine2: How do I flush correctly an entity with ArrayCollections()? 【发布时间】:2011-04-14 13:14:32 【问题描述】:

我正在开始我的第一个 Zend Framework + Doctrine 2 项目,我有一个问题。我使用 PostgreSQL 9 和 Apache 2.2 我有以下实体(实体和属性的名称仅用于此示例):

<?php
namespace Xproject\Entities;
/**
 * Entity1   
 * @Table()  
 * @Entity  
 */      
class Entity1
  
/***  
 * @var integer $ent1Code     
 * @Column(name="ent1Code", type="integer", length=4)  
 * @Id  
 * @GeneratedValue(strategy="IDENTITY")  
 */  
private $ent1Code;

/**
 * @var decimal $att1     
 * @Column(name="att1", type="decimal")
 */
private $att1;

 /** 
 * OWNING SIDE
 * @var \Doctrine\Common\Collections\ArrayCollection     
 * @ManyToOne(targetEntity="Entity2", inversedBy="entity1")
 * @JoinColumn(name="ent2Code", referencedColumnName="ent2Code")
 */
private $entity2;

/** 
 * UNIDIRECTIONAL
 * @var \Doctrine\Common\Collections\ArrayCollection
 * @ManyToOne(targetEntity="Entity3")
 * @JoinColumn(name="ent3Code", referencedColumnName="ent3Code")
 */
private $entity3;

 /**
 * UNIDIRECTIONAL
 * @var \Doctrine\Common\Collections\ArrayCollection
 * @ManyToOne(targetEntity="Entity4")
 * @JoinColumn(name="ent4Code", referencedColumnName="ent4Code")
 */
private $entity4;

public function __construct() 
    $this->entity2 = new \Doctrine\Common\Collections\ArrayCollection();
    $this->entity3 = new \Doctrine\Common\Collections\ArrayCollection();
    $this->entity4 = new \Doctrine\Common\Collections\ArrayCollection();


public function getEnt1Code()
    return $this->ent1Code;


public function getAtt1()
    return $this->att1;


public function setAtt1($value)
    $this->att1=$value;


public function addEntity2(Entity2 $value)
    $value->addEntity1($this);
    $this->entity2->add($value);


public function addEntity3(Entity3 $value)
    $this->entity3->add($value);


public function addEntity4(Entity4 $value)
    $this->entity4->add($value);
    


<?php
namespace Xproject\Entities;
/**
 * Entity2 
 * @Table()
 * @Entity
 */
class Entity2
 
/**
 * @var integer $ent2Code     
 * @Column(name="ent2Code", type="integer", length=4)
 * @Id
 * @GeneratedValue(strategy="IDENTITY")
 */
private $ent2Code;

/**
 * INVERSE SIDE
 * @var entity1    
 * @OneToMany(targetEntity="Entity1", mappedBy="entity2")
 */
private $entity1;

public function __construct() 
    $this->entity1 = new \Doctrine\Common\Collections\ArrayCollection();


public function getEnt2Code()
    return $this->ent2Code;


public function addEntity1(Entity1 $value)
    $this->entity1->add($value);



<?php
namespace Xproject\Entities;

/**
 * Entity3
 * @Table()
 * @Entity
 */
class Entity3

/**
 * @var integer $ent3Code     
 * @Column(name="ent3Code", type="integer", length=4)
 * @Id
 * @GeneratedValue(strategy="IDENTITY")
 */
private $ent3Code;

/**
 * @var string $att1     
 * @Column(name="att1", type="string", length=150)
 */
private $att1;

public function getEnt3Code()
    return $this->ent3Code;


public function getAtt1()
    return $this->att1;


public function setAtt1($value)
    $this->att1=$value;




<?php   
namespace Xproject\Entities;
/**
 * Entity4 
 * @Table()
 * @Entity
 */
 class Entity4 

/**
 * @var integer $ent4Code   
 * @Column(name="ent4Code", type="integer", length=4)
 * @Id
 * @GeneratedValue(strategy="IDENTITY")
 */
private $ent4Code;

/**
 * @var string $att1    
 * @Column(name="att1", type="string", length=150)
 */
private $att1;

public function getEnt4Code()
    return $this->ent4Code;


public function getAtt1()
    return $this->att1;


public function setAtt1($value)
    $this->att1=$value;


只是为了尝试一切正常,我在 Xproject 的 indexController 中使用以下代码:

<?php
class IndexController extends Zend_Controller_Action

    public function init()
   
        $this->doctrine = Zend_Registry::get('doctrine');
        $this->em = $this->doctrine->getEntityManager();
    

public function indexAction()

    $ent2 = new Xproject\Entities\Entity2();
    $this->em->persist($ent2);

    $ent3 = new Xproject\Entities\Entity3();
    $ent3->setAtt1('xyz');
    $this->em->persist($ent3);

    $ent4= new Xproject\Entities\Entity4();
    $ent4->setAtt1('abc');
    $this->em->persist($ent4);

    //1st flush
    $this->em->flush();                       

    $ent1= new Xproject\Entities\Entity1();
    $ent1->setAtt1(350.00);
    $ent1->addEntity2(ent2);
    $ent1->addEntity3(ent3);
    $ent1->addEntity4(ent4);
    $this->em->persist($ent1);

    //2nd flush
    //$this->em->flush();     


第一次刷新可以正常工作,并且所有内容都可以正常保存到数据库中,但是如果我同时使用第一次和第二次刷新,浏览器会显示应用程序错误并且 $ent1 根本没有保存到数据库中。 使用 var_dump($ent1) 我可以看到对象 $ent1 状态是正确的(att1 并且所有集合都加载正常)。 在加载此脚本期间,Apache 错误日志未显示任何错误或警告。 我绝对认为我在这里遗漏了一些与 ArrayCollections 以及刷新它们时它们如何工作有关的重要内容。 我错过了一些重要的东西吗?

【问题讨论】:

indexAction 的内容包围在try...catchvar_dump 异常中。 (InvalidArgumentException)#176 (7) ["message":protected]=> string(275) "通过未配置为级联持久操作的关系找到新实体:Doctrine\ Common\Collections\ArrayCollection@0000000057ee7b54000000006e20d44c。显式持久化新实体或在关系上配置级联持久化操作。” ["string":"Exception":private]=> string(0) "" ["code":protected]=> int(0) ["file":protected]=> string(115) /** * INVERSE SIDE * @var entity1 * @OneToMany(targetEntity="Entity1", mappedBy="entity2", cascade="persist") */ 添加到“cascade="persist"" 行的末尾,但仍然存在同样的问题 $ent1-&gt;addEntity2(ent2); 应该是$ent1-&gt;addEntity2($ent2); 【参考方案1】:

您的关系都是多对一,因此不应该涉及 ArrayCollections。

由于没有收藏,你不想add东西,你想set东西:

在实体 1 中:

public function setEntity2(Entity2 $entity2)
    $this->entity2 = $entity2
    return $this;

在您的控制器中:

$entity1->setEntity2($entity2);

就是这样。您像 $this->entity2->add() 这样的调用正在工作,因为您将这些属性初始化为 ArrayCollections。但教义只是无视它们。

换句话说,对于 *ToOne 关系,对象属性只是外部实体类型。将它们视为简单值,并通过典型的 set*() mutator 设置它们。

【讨论】:

这是 timdev 的问题。非常感谢大家

以上是关于Zend+Doctrine2:如何使用 ArrayCollections() 正确刷新实体?的主要内容,如果未能解决你的问题,请参考以下文章

Doctrine 2 自定义 ObjectMultiCheckbox 值

Doctrine2更新导致Zend Framework 3中的AnnotationRegistry registerLoader错误

是否可以将 Doctrine 2 与 Zend Framework 1.1x 集成?

Zend Framework 2 + Doctrine 2 [关闭]

在 Zend 框架 2 中使用 MappedSuperclass 的 Doctrine 2 多对多

zend 框架 2 + 教义 2 安装