1 つのテーブルに複数のモデルを使用することは可能ですか (推奨されますか)?
複数のタイプの「人」(教師、学生、従業員、会社)があり、それらを同じテーブルに保存したいと考えています。それらはすべて共通の個人データを持っていますが、他の関係 (例: 学生 -> 会社、教師 -> 部屋など)、追加情報 (例: 会社: 会社名、教師: 教育) などがあります。
このような場合のベスト プラクティスをいくつか得られるとよいでしょう。
1 つのテーブルに複数のモデルを使用することは可能ですか (推奨されますか)?
複数のタイプの「人」(教師、学生、従業員、会社)があり、それらを同じテーブルに保存したいと考えています。それらはすべて共通の個人データを持っていますが、他の関係 (例: 学生 -> 会社、教師 -> 部屋など)、追加情報 (例: 会社: 会社名、教師: 教育) などがあります。
このような場合のベスト プラクティスをいくつか得られるとよいでしょう。
とても簡単です!次のようなエンティティを作成する必要があります。
/**
* @ORM\Entity
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(name="discr", type="string")
* @ORM\DiscriminatorMap({"teacher" = "Teacher"})
*/
class Person
{
/**
* @ORM/Id
**/
private $id;
/**
* @ORM/Column
**/
private $name;
//setters getters and all the stuff
}
そしてTeacher.phpファイルで:
/**
* @ORM\Table()
* @ORM\Entity()
*/
class Teacher extends Person
{
private $salary;
}
成功の秘訣は、次の2つの注釈です。
@ORM\DiscriminatorColumn(name="discr", type="string")
@ORM\DiscriminatorMap({"teacher" = "Teacher"})
まず、ORMに、その人が教師であるかどうかを確認するために使用される列を指示します。2つ目は、基本のPersonクラスを拡張しているクラスと、前述の列に何を入力するかを指示することです。これを行うと、2つのテーブルが作成されますが、Teacherでは、Teacherエンティティに追加したデータのみが作成されます:)
一般的に言えば、ORMを使用するときは、オブジェクトの抽象化レベルで考える必要があり、DBについては気にしません(まあ、それは完全に真実ではありませんが、一般的な考え方です):)
お勧めしません。なぜこれをしないのか、私が考えることができるいくつかの理由を次に示します。
IBM は、リレーショナル データベースにおける継承のマッピングに関する素晴らしい投稿を行っており、このタイプのモデルを実装する際に何度か参照しました。(1) 単一のテーブルを使用してすべてのクラスを表す (提案した方法)、(2) 子クラスに個別のテーブルを使用する、(3) すべてのクラスに個別のテーブルを使用する、の 3 つの方法を参照します。最終的には個人の好みになりますが、私が通常行う方法は、すべてのクラスのモデルを作成する#2と#3のブレンドですが、子から親クラスへのアクセスを制限し、代わりに、親データにアクセスするためのショートカット メソッドを記述します。このことを考慮:
class Person
{
private $id;
private $name;
public function getId()
{ return $this->id; }
public function getName()
{ return $this->name; }
public function setName($name)
{ return $this->name; }
}
class Teacher
{
private $id;
private $person; // reference to Person table
private $salary;
public function getId()
{ return $this->id; }
private function getPerson()
{ return $this->person; }
public function getSalary()
{ return $this->salary; }
public function setSalary($salary)
{ $this->salary = $salary; }
public function getName()
{ return $this->getPerson()->getName(); }
public function setName($name)
{ $this->getPerson()->setName($name); }
}
状況に応じて、教師を単に教師として、または人として扱うことができるため、私は通常この方法を選択します。2 つのページがあるとします。1 つは全員の名前 (教師と生徒) を出力するページで、もう 1 つは教師とその給与だけを出力するページです。
// Assume:
// $people = $this->getDoctrine()->getEntityManager()->getRepository("MyBundle:Person")->findAll()
{% for person in people %}
{{ person.name }}
{% endfor %}
// Assume:
// $teachers = $this->getDoctrine()->getEntityManager()->getRepository("MyBundle:Teacher")->findAll()
{% for teacher in teachers %}
{{ teacher.name }} makes ${{ teacher.salary }}
{% endfor %}