有null对象时如何处理doctrine的延迟加载?

时间:2012-11-07 17:43:00

标签: php orm doctrine lazy-loading

我对处理学说的延迟加载机制的正确方法有疑问。我有一个实体通过@ManyToOne引用另一个实体:

class Entity {
    ...
    /**
     * @ManyToOne(targetEntity="AnotherEntity")
     * @JoinColumn(name="anotherEntityId", referencedColumnName="id")
     */
    protected $anotherEntity;
    ...
}

class AnotherEntity {
    /**
     * @var integer $id
     * @Column(name="id", type="integer", nullable=false)
     * @Id
     * @GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string $someValue
     * @Column(name="someValue", type="string")
     */
    private $someValue;
    ...
}

Doctrine现在为AnotherEntity生成一个代理,在其getter上实现延迟加载:

public function getSomeValue()
{
    $this->__load();
    return parent::getSomeValue();
}

如果我现在有一些Entity实例没有AnotherEntity的引用副本($ anotherEntityId为0或null)。然后,doctrine似乎生成了AnotherEntity的一个null-Object,并使所有Entity对象的$ anotherEntity变量指向它。由于我们需要延迟加载,因此null对象未初始化。 我现在得到一个EntityNotFoundException:

$entiy->getAnotherEntity()->getSomeValue();

太棒了!我访问的AnotherEntity在数据库中不存在,因此我得到了这个异常。 但是当我对第二个实体(以及之后的所有其他实体)执行相同操作时,我没有得到此异常,因为它们都指向AnotherEntity的相同实例,并且在第一次调用中将其标记为初始化。所以现在我正在访问一个逻辑上不存在但没有任何异常的对象 - 我只是从getSomeValue()获取未初始化的变量,例如一个空字符串。

您是否知道如何让我的应用程序识别该对象不存在而不仅仅是接受空值?

2 个答案:

答案 0 :(得分:2)

我猜这是一个教条的错误,因为代理被标记为已初始化,即使它不是在抛出EntityNotFoundException时也是如此。以下是为每个代理生成的代码原则:

public function __load()
{
    if (!$this->__isInitialized__ && $this->_entityPersister) {
        $this->__isInitialized__ = true;

        if (method_exists($this, "__wakeup")) {
            // call this after __isInitialized__to avoid infinite recursion
            // but before loading to emulate what ClassMetadata::newInstance()
            // provides.
            $this->__wakeup();
        }

        if ($this->_entityPersister->load($this->_identifier, $this) === null) {
            throw new \Doctrine\ORM\EntityNotFoundException();
        }
        unset($this->_entityPersister, $this->_identifier);
    }
}

在ProxyFactory文件中,您可以找到此代码,并在抛出异常之前添加以下行,问题就解决了:

$this->__isInitialized__ = false;

通过这种方式,您可以在每次需要时获得例外。

顺便说一下:人们已经讨论了这个问题,然而这个问题似乎没有出现在当前版本中:https://github.com/doctrine/doctrine2/pull/364

答案 1 :(得分:0)

这是关于学说2的错误,请参阅https://github.com/doctrine/doctrine2/issues/3945

用户和地址之间的关系是一到零或一。当双方都有记录时,一切都很顺利。当右侧(地址)没有相关记录时,调用$user->getAddress();总是返回一个实例。在该实例上调用方法会导致异常:

  

致命错误:未捕获的异常' Doctrine \ ORM \ EntityNotFoundException'使用消息'实体类型'地址'没找到。'在第176行的doctrine / orm / lib / Doctrine / ORM / Proxy / ProxyFactory.php中

预期行为: 当右侧为空时,$user->getAddress()应该返回NULL。

注意: 请注意,地址是通过外国实体(用户)识别的