我正在使用Zend Framework 3和Doctrine ORM进行Web项目。
我的应用程序中有几个模块(User
、Stock
、Sales
),每个模块上都有一些实体模型:
User
模块实体:User
、Account
等。Stock
模块实体:SKU
、StockLevel
等。Sales
模块实体:Invoice
、PaymentMethod
等。
默认情况下,所有实体都有公共字段,例如:
creationDateTime
: 创建日期/时间creationUser
:创建实体的用户lastChangeDateTime
:上次实体更改的日期/时间lastChangeUser
:上次更改实体的用户
我不想放置这些字段或每个实体,而是创建一个将扩展我所有实体的项目基类。我需要有适用于所有实体的通用方法,即:
/**
* Update the last change fields
* @param string $user User that is updating
*/
public void updateLastChange($user)
{
$this->lastChageDataTime = Datetime();
$this->lastChangeUser = $user;
}
正如我从文档中看到的那样,它看到我需要使用单个表继承,但我无法弄清楚确切的方式。问题:
a)通过使用单表继承,Doctrine 会在数据库中为这些字段创建一个基表,还是会为每个实体表连接基字段和实体字段,或者换句话说,我会只拥有实体表还是此继承也会为基字段创建一个数据库表?
b)我应该把我的基本实体放在哪里,以便它可以继承到不同模块上的所有实体?
我希望有人可以放一些关于如何做到这一点的例子/链接。
对于你想要做的事情,单表继承不是你需要的。
有 2 个选项:
1)映射超级类(几乎直接来自文档)
你创建一个MappedSuperClass
(文档可以在第6.1 章:映射的超类中找到),并在该基类中添加这些公共字段。然后,从基(映射的超)类中扩展需要这些字段的所有类。
/**
* @MappedSuperclass
*/
class MappedSuperclassBase
{
/** @Column(type="datetime") */
protected $creationDateTime;
/**
* @ManyToOne(targetEntity="ApplicationEntityUser")
* @JoinColumn(name="created_by", referencedColumnName="id")
*/
protected $creationUser;
/** @Column(type="datetime") */
protected $lastChangeDateTime;
/**
* @ManyToOne(targetEntity="ApplicationEntityUser")
* @JoinColumn(name="updated_by", referencedColumnName="id")
*/
protected $lastChangeUser;
// ... more fields and methods
}
/**
* @Entity
*/
class EntitySubClass extends MappedSuperclassBase
{
/** @Id @Column(type="integer") */
private $id;
// ... more fields and methods
}
2)您使用特质
你创建一个特征(或每个字段/关联的几个单独的特征),你可以在所有需要具有这些公共字段的类中使用。
trait BaseTrait
{
/** @Column(type="datetime") */
protected $creationDateTime;
/**
* @ManyToOne(targetEntity="ApplicationEntityUser")
* @JoinColumn(name="created_by", referencedColumnName="id")
*/
protected $creationUser;
/** @Column(type="datetime") */
protected $lastChangeDateTime;
/**
* @ManyToOne(targetEntity="ApplicationEntityUser")
* @JoinColumn(name="updated_by", referencedColumnName="id")
*/
protected $lastChangeUser ;
// ... more fields and methods
}
/**
* @Entity
*/
class EntitySubClass
{
use BaseTrait;
/** @Id @Column(type="integer") */
private $id;
// ... more fields and methods
}
回答您的问题:
a)在文档中,您可以阅读:
单表继承是一种继承映射策略,其中层次结构的所有类都映射到单个数据库表。为了区分哪一行代表层次结构中的哪种类型,使用了所谓的鉴别器列。
这意味着所有这些实体将共享一个公共表,这绝对不是您想要的。它可能会变成一个巨大的表(每个实体的一行),减慢您的查询速度。除此之外,表中还将有所有不常用共享字段的列,对于没有这些字段的实体,这些列将为空(null
)。这也意味着那些非共享字段不能具有null
约束。再次直接从文档中:
要使单表继承适用于使用旧数据库架构或自写数据库架构的情况,您必须确保不在根实体中但位于任何不同子实体中的所有列都必须允许 null 值。没有 NULL 约束的列必须位于单表继承层次结构的根实体上。
这种继承仅对于类似于巨大扩展的实体是必需的,并且不适合您在问题中谈论的示例。
b) 您可以将基本实体(即MappedSuperClass
)添加到公共模型(如Application
文件夹)中。