我目前有一个如下的模型结构:
/**
* @ORMEntity
* @ORMInheritanceType("JOINED")
* @ORMDiscriminatorColumn(name="related_type", type="string")
* @ORMDiscriminatorMap({"type_one"="TypeOne", "type_two"="TypeTwo"})
*/
abstract class BaseEntity {
... (all the usual stuff, IDs, etc)
/**
* @ORMOneToMany(targetEntity="Comment", mappedBy="baseEntity")
*/
private $comments;
}
/**
* @ORMEntity
*/
class TypeOne extends BaseEntity {
/**
* @ORMColumn(type="string")
*/
private $name;
/**
* @ORMColumn(type="string")
*/
private $description;
}
/**
* @ORMEntity
*/
class TypeTwo extends BaseEntity {
/**
* @ORMColumn(type="string")
*/
private $name;
/**
* @ORMColumn(type="string")
*/
private $description;
}
/**
* @ORMEntity
*/
class Comment {
... (all the usual stuff, IDs, etc)
/**
* @ORMManyToOne(targetEntity="BaseEntity", inversedBy="comments")
*/
private $baseEntity;
}
这里的想法是能够将注释绑定到任何其他表。到目前为止,这一切似乎都还可以(当然,我仍在探索设计选项,所以可能有更好的方法…),但我注意到的一件事是,子类有一些公共字段,我想将它们移到一个公共父类中。我不想把它们移到BaseEntity中,因为还会有其他对象是BaseEntity的子对象,但它们不会有这些字段。
我考虑过在中间创建一个MappedSuperclass父类,如下所示:
/**
* @ORMMappedSuperclass
*/
abstract class Common extends BaseEntity {
/**
* @ORMColumn(type="string")
*/
private $name;
/**
* @ORMColumn(type="string")
*/
private $description;
}
/**
* @ORMEntity
*/
class TypeOne extends Common {}
/**
* @ORMEntity
*/
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。在这种情况下,类表继承或单表(如果您愿意)将完美工作。
如果您的数据遵循该示例,请使用"单表"或"类表继承"。如果没有,我可能建议不要对字段进行分组。