是否可以(并且推荐)为一个表使用多个模型?
我有多种类型的"人"(教师、学生、员工、公司),我想把它们放在同一张桌子上。他们有所有共同的个人数据,但有其他关系(例如学生->公司、教师->房间等)、额外信息(例如公司:公司名称、教师:教育)等。
如果能为这种情况提供一些最佳实践,那就太好了。
这真的很简单!你必须制作这样的实体:
/**
* @ORMEntity
* @ORMInheritanceType("JOINED")
* @ORMDiscriminatorColumn(name="discr", type="string")
* @ORMDiscriminatorMap({"teacher" = "Teacher"})
*/
class Person
{
/**
* @ORM/Id
**/
private $id;
/**
* @ORM/Column
**/
private $name;
//setters getters and all the stuff
}
在Teacher.php文件中:
/**
* @ORMTable()
* @ORMEntity()
*/
class Teacher extends Person
{
private $salary;
}
成功的关键在于这两个注释:
@ORMDiscriminatorColumn(name="discr", type="string")
@ORMDiscriminatorMap({"teacher" = "Teacher"})
首先是告诉ORM将使用哪一列来验证此人是否为教师。第二个是告诉哪些类正在扩展基本Person类,以及在我前面提到的专栏中放什么。当你这样做时,你会有两个表,但在Teacher中,你只有添加到Teacher实体的数据:)
一般来说,当使用ORM时,你必须考虑对象抽象级别,而不关心DB(好吧,这并不完全正确,但这是一般的想法):)
不推荐使用。以下是我能想到为什么不这样做的几个原因:
- 如果教师和学生共享同一组ID,如何阻止某人使用学生ID加载教师,并在"工资"字段中添加值?可以限制这种访问,但可能需要自定义存储库或其他修改
- 比方说,教师必须有工资。如果学生和教师共享同一个表,那么数据库将无法在不给学生工资的情况下强制执行该约束
- 尽管学生永远不会有薪水,但无论如何,数据库可能需要为该字段分配空间
IBM有一篇关于在关系数据库中映射继承的好文章,在实现这种类型的模型时我已经多次提到它。它们引用了三种方法:(1)使用一个表来表示所有类(您提出的方法),(2)为子类使用单独的表,或(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); }
}
我通常选择这种方法是因为我可以把一个老师简单地当作一个老师,或者当作一个人,这取决于情况的需要。假设我有两页:一页打印出每个人的姓名(教师和学生),另一页只打印出教师和他们的工资:
// 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 %}