我有以下实体:
class Restaurant
{
/**
* @OneToMany(targetEntity="CollectionTime", mappedBy="restaurant")
*/
protected $collectionTimes;
/**
* @OneToMany(targetEntity="DeliveryTime", mappedBy="restaurant")
*/
protected $deliveryTimes;
}
映射到同一实体的两个子类:
/**
* @Entity
* @InheritanceType("SINGLE_TABLE")
* @ORM\DiscriminatorMap({
* "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&#39 ;属性。
字段Restaurant#deliveryTimes位于双向关系的反面,但目标实体DeliveryTime#restaurant上指定的mappedBy关联不包含所需的' inversedBy = deliveryTimes&#39 ;属性。
简而言之,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,但它们似乎并不是为此而设计的。
答案 0 :(得分:7)
Doctrine 2使用单向关联和双向关联的概念。
定义单向关联时,必须省略inversedBy
参数,因为关联不会被反转。
定义双向关联时,您必须使用拥有方上的inversedBy
参数(实际上包含Doctrine所有元数据的一方,以正确映射关联),你必须在反面上使用mappedBy
参数(以便Doctrine知道在哪里寻找关联的实际映射元数据)。
因此,您要么同时使用inversedBy
和 mappedBy
(双向),要么完全使用它们(单向)
但它很麻烦,违背了继承原则。
我认为这取决于你如何看待它:
如果你只看代码(而不是映射),那你就是对的。 OrderTime
的两个具体实现共享属性$restaurant
(可能还有getter,setter和其他逻辑),因此原则要求您在OrderTime
中定义它。
但是当您查看映射时,您有2个不同的关联:一个将Restaurant::$collectionTimes
和CollectionTime::$restaurant
联系在一起,另一个关联Restaurant::$deliveryTimes
和DeliveryTime::$restaurant
在一起。
因为这些是两种不同的关联,所以Doctrine希望您正确地定义它们是公平的。
您仍然可以通过以下方式坚持继承原则:在OrderTime
中定义所需的所有共享逻辑,甚至是属性$restaurant
,只是不添加映射元数据。在具体实现中,您可以使用正确的映射元数据重新声明属性$restaurant
。
您必须在这些混凝土中重新声明属性$restaurant
的唯一原因是您正在使用Annotations来映射元数据。使用Yaml或XML时,您不必重新声明属性,因为映射元数据将位于单独的文件中。
事实上,它不是你在这些具体实现中定义的代码/逻辑,而是映射元数据。
这些OrderTime
类看起来更像Value Objects给我(不是实体):A small simple object, like money or a date range, whose equality isn't based on identity.
Doctrine将支持从2.5版开始的值对象(see here)。
答案 1 :(得分:3)
您可以覆盖自Doctrine 2.6(几天前发布)以来的inversedBy
。那看起来像那样:
/**
* @Entity
* @ORM\AssociationOverrides({
* @ORM\AssociationOverride(name="restaurant", inversedBy="collectionTimes")
* })
*/
class CollectionTime extends OrderTime
{
}
/**
* @Entity
* @ORM\AssociationOverrides({
* @ORM\AssociationOverride(name="restaurant", inversedBy="deliveryTimes")
* })
*/
class DeliveryTime extends OrderTime
{
}