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


Symfony2 / Doctrine mapped superclass in the middle of class table inheritance

我目前有一个如下的模型结构:

/**
 * @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 {}

我认为这会起作用,但条令数据库模式生成器抱怨我不能在MappedSuperclass上有OneToMany映射。我没想到这会成为一个问题,因为OneToMany映射仍然在根BaseEntity和Comment表之间。我是否应该使用不同的结构,或者以其他方式使这些字段通用,而不将它们添加到BaseEntity中?

从文档:

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

也就是说,你怎么能把一个实体和一个非实体联系起来?

更多文档:

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

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


更新

因为MappedSuperClass扩展了BaseEntity,所以它也继承了BaseEntity的关联,就好像它是自己的一样。因此,您实际上在MappedSuperClass上有一个OneToMany。

为了绕过它,你需要修改/扩展原则,以按照你想要的方式工作。

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

类表继承Common类和由此产生的DB表示将具有公共字段,而子类现在将只具有特定于它们自己的字段。不幸的是,如果您只是为了分组而对公共字段进行分组,那么这可能是对数据的歪曲。

使公共成为一个实体似乎所有映射的超级类都是一个未在DB中表示的实体。因此,将公共实体改为实体。不利的一面是,您最终会得到一个DB表,但您可以直接删除它。

我建议您重新查看数据,并确保只有在名称和目的都通用的情况下才对字段进行分组。例如,一个ComputerBox、一个ShoeBox、一个Man和一个Woman可能都具有"height"属性,但在这种情况下,我不建议使用一个Common类,该类都继承自该类。相反,我会有一个具有ComputerBox和ShoeBox公用字段的Box,我会拥有一个具有Man和Woman公用字段的Person。在这种情况下,类表继承或单表(如果您愿意)将完美工作。

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