1

doctrineの遅延読み込みメカニズムを処理する正しい方法について質問があります。@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のプロキシを生成するようになりました。

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

これで、AnotherEntityの参照対応物を持たないEntityのインスタンスがいくつかある場合($ anotherEntityIdは0またはnull)。次に、doctrineはAnotherEntityの1つのnull-Objectを生成し、すべてのEntityオブジェクトの$anotherEntity変数がそれを指すようにします。遅延読み込みが必要なため、nullオブジェクトは初期化されていません。これを行うと、EntityNotFoundExceptionが発生します。

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

それは素晴らしいことです!アクセスするAnotherEntityがデータベースに存在しないため、この例外が発生します。しかし、2番目のエンティティ(およびその後の他のすべて)で同じことを行うと、この例外は発生しません。これらはすべて、AnotherEntityの同じインスタンスを指しており、教義は最初の呼び出しで初期化されたものとしてマークしているためです。したがって、論理的には存在しないが例外は発生しないオブジェクトにアクセスしています。getSomeValue()から初期化されていない変数(空の文字列など)を取得するだけです。

空の値を受け入れるだけでなく、オブジェクトが存在しないことをアプリケーションに認識させる方法を知っていますか?

4

2 に答える 2

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

于 2012-11-12T10:09:22.143 に答える
0

これはDoctrine2のバグです。https://github.com/doctrine/doctrine2/issues/3945を参照してください。

ユーザーとアドレスの関係は1対0または1です。レコードが両側に存在する場合、すべてがうまくいきます。右側(アドレス)に関連するレコードがない場合、呼び出し$user->getAddress();は常にインスタンスを返します。そのインスタンスでメソッドを呼び出すと、例外が発生します。

致命的なエラー:キャッチされない例外'Doctrine \ ORM\EntityNotFoundException'とメッセージ'タイプ'アドレス'のエンティティが見つかりませんでした。doctrine / orm / lib / Doctrine / ORM / Proxy/ProxyFactory.phpの176行目

期待される動作: $user->getAddress()右側が空の場合はNULLを返す必要があります。

注:アドレスは外国のエンティティ(ユーザー)によって識別されることに注意してください

于 2017-11-24T19:43:25.070 に答える