在持久化新实体时插入NULL,将表列映射到2个表.原则2


NULL inserted while Persisting new Entity, Mapping table column to 2 tables. doctrine 2

我需要将相同的列映射到2个不同的表(让我们说正常和扩展)。

 /**
 * @var ItemValue
 *
 * @OneToOne(targetEntity="ItemValue")
 * @JoinColumn(name="id_value", referencedColumnName="id_value")
 */
private $value;
 /**
 * @var ItemValueExtended
 *
 * @OneToOne(targetEntity="ItemValueExtended")
 * @JoinColumn(name="id_value", referencedColumnName="id_value")
 */
private $valueExtended;
/**
 * @var string $isExtended
 *
 * @Column(name="is_extended", type="string", nullable=false)
 */
private $isExtended = 'YES';

我对使用DQL连接基于isExtended属性的数据没有问题:

 "SELECT id,idv FROM ItemData id 
      JOIN id.value idv WHERE  id.isExtended='NO'";

 "SELECT id,idv FROM ItemData id 
      JOIN id.valueExtended idv WHERE  id.isExtended='YES'";

但是当我想持久化一个新对象时,在id_value列中插入NULL ?!!

 $oValue = ItemValue();
 .
 .
 $oData = new ItemData();
 $oData->setValue($oValue);
 .
 .
 .
 $em->persist($oData);
 $em->flush();

来自Doctrine2文档:

在双向关联的情况下,必须更新

一个可能的解决方案是:

$oData = new ItemData();
$oData->setValue($oValue);
$oValue->setData($oData);

但是很乏味。另一个更好的是在一对一关联的两边设置级联选项:

@OneToOne(targetEntity="ItemValue"), cascade={"persist", "remove"})

这样你的代码就可以工作了。您可以在这里选择合适的级联选项。

在父实体和子实体都是新实体(都没有持久化)的情况下,父实体上的PrePersist生命周期事件可以提供帮助:

/**
 * ....
 *
 * @ORM'HasLifecycleCallbacks
 */
class ParentEntity {...
/**
 * @ORM'PrePersist()
 */
public function prePersist() {
    foreach($this->getChildEntities() as $childEntity) {
        $childEntity->setParent($this);
    }
}

class ChildEntity {
....

这将在保存父节点时自动创建child -> parent关系。在许多情况下,Doctrine将能够在SQL级别解决其余的问题。