覆盖Doctrine 2继承中的inversedBy映射

时间:2014-03-30 15:11:29

标签: doctrine-orm

我有以下实体:

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属性并映射到CollectionTimeDeliveryTime,以便能够添加正确的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,但它们似乎并不是为此而设计的。

2 个答案:

答案 0 :(得分:7)

单向/双向

Doctrine 2使用单向关联和双向关联的概念。

定义单向关联时,必须省略inversedBy参数,因为关联不会被反转。

定义双向关联时,您必须使用拥有方上的inversedBy参数(实际上包含Doctrine所有元数据的一方,以正确映射关联),你必须在反面上使用mappedBy参数(以便Doctrine知道在哪里寻找关联的实际映射元数据)。

因此,您要么同时使用inversedBy mappedBy(双向),要么完全使用它们(单向)

继承原则

  

但它很麻烦,违背了继承原则。

我认为这取决于你如何看待它:

如果你只看代码(而不是映射),那你就是对的。 OrderTime的两个具体实现共享属性$restaurant(可能还有getter,setter和其他逻辑),因此原则要求您在OrderTime中定义它。

但是当您查看映射时,您有2个不同的关联:一个将Restaurant::$collectionTimesCollectionTime::$restaurant联系在一起,另一个关联Restaurant::$deliveryTimesDeliveryTime::$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
{
}