Symfony2 / Doctrine在类表继承中间映射了超类

时间:2012-08-30 17:32:28

标签: php database symfony doctrine-orm

我目前的模型结构如下:

/**
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="related_type", type="string")
 * @ORM\DiscriminatorMap({"type_one"="TypeOne", "type_two"="TypeTwo"})
 */
abstract class BaseEntity {

    ... (all the usual stuff, IDs, etc)

    /**
     * @ORM\OneToMany(targetEntity="Comment", mappedBy="baseEntity")
     */
    private $comments;
}

/**
 * @ORM\Entity
 */
class TypeOne extends BaseEntity {
    /**
     * @ORM\Column(type="string")
     */
    private $name;

    /**
     * @ORM\Column(type="string")
     */
    private $description;
}

/**
 * @ORM\Entity
 */
class TypeTwo extends BaseEntity {
    /**
     * @ORM\Column(type="string")
     */
    private $name;

    /**
     * @ORM\Column(type="string")
     */
    private $description;   
}

/**
 * @ORM\Entity
 */
class Comment {

    ... (all the usual stuff, IDs, etc)

    /**
     * @ORM\ManyToOne(targetEntity="BaseEntity", inversedBy="comments")
     */
    private $baseEntity;
}

这里的想法是能够将评论与任何其他表格联系起来。到目前为止,这一切似乎都运行正常(授予,我仍然在探索设计选项,因此可以有更好的方法来实现这一点......),但我注意到的一件事是子类有一些共同的字段我想进入一个共同的父类。我不想将它们移动到BaseEntity中,因为会有其他对象是BaseEntity的子对象,但是不会有这些字段。

我考虑在中间创建一个MappedSuperclass父类,如下所示:

/**
 * @ORM\MappedSuperclass
 */
abstract class Common extends BaseEntity {
    /**
     * @ORM\Column(type="string")
     */
    private $name;

    /**
     * @ORM\Column(type="string")
     */
    private $description;       
}

/**
 * @ORM\Entity
 */
class TypeOne extends Common {}

/**
 * @ORM\Entity
 */
class TypeTwo extends Common {}

我认为这样可行,但是doctrine数据库模式生成器抱怨我不能在MappedSuperclass上有一个OneToMany映射。我不认为这是一个问题,因为OneToMany映射仍然在根BaseEntity和Comment表之间。是否有我应该使用的不同结构,或其他方式使这些字段不同而不在BaseEntity上添加它们?

1 个答案:

答案 0 :(得分:14)

来自文档:

  

映射的超类是提供的抽象或具体类   持久化实体状态及其子类的映射信息,   但它本身不是一个实体。通常,这样的目的   映射的超类是定义状态和映射信息   多个实体类共有。

那就是说,如何将一个实体与一个实体相关联?

更多来自文档:

  

映射的超类不能是实体,它不可查询和   由映射的超类定义的持久关系必须是   单向的(仅限拥有方)。 这意味着一对多   根本不可能在映射的超类上进行关联。   此外,只有映射后,才能实现多对多关联   超类目前仅用于一个实体。对于   进一步支持继承,单个或连接表继承   必须使用功能。

来源:http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html


<强>更新

因为MappedSuperClass扩展了BaseEntity,它也会继承BaseEntity的关联,就像它自己的关联一样。所以你有效地在MappedSuperClass上有一个OneToMany。

要解决它,嗯,你需要修改/扩展学说以按照你想要的方式工作。

就本机功能而言,您有两种选择:

类表继承 您的公共类和生成的数据库表示将具有公共字段,子类现在将只具有特定于自身的字段。不幸的是,如果您只是为了对它们进行分组而尝试对公共字段进行分组,这可能是对您数据的误传。

使共同体成为实体 似乎所有Mapped Super Class都是未在DB中表示的实体。所以,改为使实体成为共同体。缺点是你最终会得到一个数据库表,但你可以删除它。

我建议您再看一下您的数据,并确保您只对字段进行分组,如果它们在名称和用途上都很常见。例如,ComputerBox,ShoeBox,Man和Woman都可能具有“height”属性,但在这种情况下,我不建议使用具有“height”属性的Common类,它们都继承自。相反,我会有一个Box与ComputerBox和ShoeBox共有的字段,我会有一个人与男人和女人共同的字段。在那种情况下,如果您愿意,Class Table Inheritance或单个表将完美地运行。

如果您的数据遵循该示例,请使用单表或类表继​​承。如果没有,我可能会建议不要对这些字段进行分组。