18

これらのクラスを使用して、「Person」のレコードを「Employee」に変更するにはどうすればよいでしょうか。

/**
 * @Entity
 * @InheritanceType("SINGLE_TABLE")
 * @DiscriminatorColumn(name="discr", type="string")
 * @DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
 */
class Person
{
    // ...
}

/**
 * @Entity
 */
class Employee extends Person
{
    // ...
}

識別子列の値を変更しようとしましたが、アクセスできません。また、「従業員」インスタンスを作成してデータを手動でコピーしようとしましたが、自動インクリメント ID では機能しません。既存のレコードを更新するのではなく、新しいレコードとして追加されるだけです。

カスタム SQL クエリを作成する必要がありますか、それとも根本的に間違っていることをしていますか?

4

1 に答える 1

48

オブジェクトのインスタンスのタイプを時間の経過とともに変更する必要がある場合、これは良い兆候ではありません。ここではダウンキャスト/アップキャストについて話しているのではなく、オブジェクトの実際のタイプを変更する必要性について話しているのです。

まず、それが悪い考えである理由をお話ししましょう。

  1. サブクラスは、より多くの属性を定義し、そのコンストラクターで追加の作業を行う場合があります。新しいコンストラクターを再度実行する必要がありますか?古いオブジェクトの属性の一部を上書きするとどうなりますか?
  2. コードの一部でそのPersonのインスタンスを操作していて、それが突然Employeeに変換された場合はどうなりますか(予期しない動作が再定義されている可能性があります)。

これが、ほとんどの言語で実行中にオブジェクトの実際のクラスタイプを変更できない理由の一部です(もちろん、メモリですが、詳細には触れたくありません)。一部のユーザーはそれを実行できますが(JVMなど、ねじれた方法で実行できる場合もあります)、実際には適切な方法ではありません。

多くの場合、そうする必要があるのは、オブジェクト指向の設計上の不適切な決定にあります。

これらの理由により、Doctrineではエンティティオブジェクトのタイプを変更することはできません。もちろん、プレーンSQLを記述して(この投稿の最後にありますが、読み通してください!)、とにかく変更を行うこともできますが、ここに2つの「クリーンな」オプションを提案します。

最初のオプションはオプションではないと既におっしゃっていたと思いますが、この投稿を書き留めるのにしばらく時間を費やしたので、将来の参考のためにできるだけ完全なものにする必要があると思います。

  1. 「タイプを」からに「変更」する必要がある場合は常にPersonEmployeeEmployeeの新しいインスタンスを作成し、コピーするデータを古いPersonオブジェクトからEmployeeオブジェクトにコピーします。古いエンティティを削除し、新しいエンティティを永続化することを忘れないでください。
  2. 継承の代わりに構成を使用します(詳細と他の記事へのリンクについては、このwikiの記事を参照してください)。編集:それの地獄のために、ここに「継承上の構成」についてのエーリヒ・ガンマとの素晴らしい会話の一部があります!

ここここで関連する議論を参照してください。


さて、これが私が以前に話していたプレーンSQLメソッドです-あなたがそれを使う必要がないことを願っています!

クエリがサニタイズされていることを確認してください(クエリは検証なしで実行されるため)。

$query = "UPDATE TABLE_NAME_HERE SET discr = 'employee' WHERE id = ".$entity->getId();
$entity_manager->getConnection()->exec( $query );

DBAL\Connectionクラスにあるexecメソッドのドキュメントとコードは次のとおりです(参考までに)。

/**
 * Execute an SQL statement and return the number of affected rows.
 *
 * @param string $statement
 * @return integer The number of affected rows.
 */
public function exec($statement)
{
    $this->connect();
    return $this->_conn->exec($statement);
}
于 2012-09-27T02:55:03.580 に答える