4

我正在为我的 Web 项目使用 Zend Framework 3 和 Doctrine ORM。

我的应用程序中有几个模块(User, Stock, Sales),每个模块上有一些实体模型:

  • User模块实体:UserAccount等。
  • Stock模块实体:SKUStockLevel等。
  • Sales模块实体:InvoicePaymentMethod等。

默认情况下,所有实体都有公共字段,例如:

  • 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)我应该把我的基础实体放在哪里,以便它可以被不同模块上的所有实体继承?

我会很感激有人可以提供一些示例/链接来说明如何做到这一点。

4

1 回答 1

10

对于您想要做的单表继承不是您所需要的。

有2个选项:

1)MappedSuperClass(几乎直接来自文档)

您制作了一个MappedSuperClass(文档可以在第6.1 章:映射的超类中找到),然后在该基类中添加这些公共字段。然后,您从基类(映射的超类)中扩展所有需要这些字段的类。

/** 
 * @MappedSuperclass 
 */
class MappedSuperclassBase
{
    /** @Column(type="datetime") */
    protected $creationDateTime;

    /** 
     * @ManyToOne(targetEntity="Application\Entity\User") 
     * @JoinColumn(name="created_by", referencedColumnName="id")
     */
    protected $creationUser;

    /** @Column(type="datetime") */
    protected $lastChangeDateTime;

    /** 
     * @ManyToOne(targetEntity="Application\Entity\User") 
     * @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="Application\Entity\User") 
     * @JoinColumn(name="created_by", referencedColumnName="id")
     */
    protected $creationUser;

    /** @Column(type="datetime") */
    protected $lastChangeDateTime;

    /** 
     * @ManyToOne(targetEntity="Application\Entity\User") 
     * @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约束。再次直接来自文档:

要使单表继承在您使用旧数据库模式或自写数据库模式的情况下工作,您必须确保所有不在根实体中但在任何不同子实体中的列必须允许空值。具有 NOT NULL 约束的列必须位于单表继承层次结构的根实体上。

这种继承仅对类似于巨大扩展的实体是必需的,并且不适合您在问题中讨论的示例。

b)您可以MappedSuperClass在通用模型(例如您的Application文件夹)中添加基本实体(因此)。

于 2016-11-28T16:06:35.380 回答