覆盖Doctrine 2继承中的inversedBy映射
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了覆盖Doctrine 2继承中的inversedBy映射相关的知识,希望对你有一定的参考价值。
我有以下实体:
class Restaurant
{
/**
* @OneToMany(targetEntity="CollectionTime", mappedBy="restaurant")
*/
protected $collectionTimes;
/**
* @OneToMany(targetEntity="DeliveryTime", mappedBy="restaurant")
*/
protected $deliveryTimes;
}
映射到同一实体的两个子类:
/**
* @Entity
* @InheritanceType("SINGLE_TABLE")
* @ORMDiscriminatorMap({
* "CollectionTime" = "CollectionTime",
* "DeliveryTime" = "DeliveryTime"
* })
*/
abstract class OrderTime
{
/**
* @ManyToOne(targetEntity="Restaurant")
*/
protected $restaurant;
}
/**
* @Entity
*/
class CollectionTime extends OrderTime
{
}
/**
* @Entity
*/
class DeliveryTime extends OrderTime
{
}
现在问题是,doctrine orm:validate-schema
报告以下错误:
- 字段Restaurant#collectionTimes位于双向关系的反面,但目标实体CollectionTime#restaurant上指定的mappedBy关联不包含所需的'inversedBy = collectionTimes'属性。
- 字段Restaurant#deliveryTimes位于双向关系的反面,但目标实体DeliveryTime#restaurant上指定的mappedBy关联不包含所需的'inversedBy = deliveryTimes'属性。
简而言之,Doctrine希望每个mappedBy
在另一边都有一个inversedBy
。
到目前为止,我能看到的唯一解决方案是移动OrderTime::$restaurant
属性并映射到CollectionTime
和DeliveryTime
,只是为了能够添加正确的inversedBy
映射:
abstract class OrderTime
{
}
/**
* @Entity
*/
class CollectionTime extends OrderTime
{
/**
* @ManyToOne(targetEntity="Restaurant", inversedBy="collectionTimes")
*/
protected $restaurant;
}
/**
* @Entity
*/
class DeliveryTime extends OrderTime
{
/**
* @ManyToOne(targetEntity="Restaurant", inversedBy="deliveryTimes")
*/
protected $restaurant;
}
但它很麻烦,违背了继承原则。
有没有办法只是覆盖子类中的inversedBy
属性,而不必(重新)声明子类中的整个属性?
我已经研究过@AssociationOverrides和@AttributeOverrides,但它们似乎并不是为此而设计的。
Unidirectional / bidirectional
Doctrine 2使用单向关联和双向关联的概念。
定义单向关联时,必须省略inversedBy
参数,因为关联不会被反转。
在定义双向关联时,您必须在拥有方使用inversedBy
参数(实际上包含Doctrine的所有元数据以正确映射关联的一侧),并且您必须在反向侧使用mappedBy
参数(以便使用Doctrine)知道在哪里寻找关联的实际映射元数据)。
所以你要么使用inversedBy
和mappedBy
(双向),要么根本不使用它们(单向)。
Principle of inheritance
但它很麻烦,违背了继承原则。
我认为这取决于你如何看待它:
如果你只看代码(不是映射),你是对的。 OrderTime
的两个具体实现共享一个属性$restaurant
(可能是getter,setter,也许还有其他逻辑),因此原则要求你在OrderTime
中定义它。
但是当你看到映射时,你有两种不同的联想:一种将Restaurant::$collectionTimes
和CollectionTime::$restaurant
联系在一起,另一种将Restaurant::$deliveryTimes
和DeliveryTime::$restaurant
联系在一起。
因为这些是两种不同的关联,所以Doctrine希望您正确地定义它们是公平的。
您仍然可以通过以下方式坚持继承原则:在OrderTime
中定义所需的所有共享逻辑,甚至是属性$restaurant
,只是不添加映射元数据。在具体实现中,您可以使用正确的映射元数据重新声明属性$restaurant
。
您必须在这些混凝土中重新声明属性$restaurant
的唯一原因是您使用Annotations来映射元数据。使用Yaml或XML时,您不必重新声明属性,因为映射元数据将位于单独的文件中。
所以实际上它不是你在那些具体实现中定义的代码/逻辑,而是映射元数据。
Value Object
那些OrderTime
类看起来更像Value Objects给我(不是实体):A small simple object, like money or a date range, whose equality isn't based on identity.
Doctrine将支持从2.5版开始的Value Objects(see here)。
你可以在Doctrine 2.6(几天前发布)之后覆盖inversedBy
。那看起来像那样:
/**
* @Entity
* @ORMAssociationOverrides({
* @ORMAssociationOverride(name="restaurant", inversedBy="collectionTimes")
* })
*/
class CollectionTime extends OrderTime
{
}
/**
* @Entity
* @ORMAssociationOverrides({
* @ORMAssociationOverride(name="restaurant", inversedBy="deliveryTimes")
* })
*/
class DeliveryTime extends OrderTime
{
}
以上是关于覆盖Doctrine 2继承中的inversedBy映射的主要内容,如果未能解决你的问题,请参考以下文章
doctrine2 映射覆盖从 MappedSuperclass 继承的 inversedBy 字段。