【问题标题】:Polymorphic relationships with Doctrine2与 Doctrine2 的多态关系
【发布时间】:2011-10-23 22:18:36
【问题描述】:

如何使用 Doctrine 2 创建传统的多态关系?

我已经阅读了很多建议使用单表继承的答案,但我看不出这对我的情况有何帮助。这是我正在尝试做的事情:

我有一些实用实体,例如地址、电子邮件和电话号码。

我有一些“可联系”实体,例如客户、雇主、企业。其中每一个都应包含与上述实用程序实体的 OneToMany 关系。

理想情况下,我想创建一个名为“ContactableEntity”的抽象基类,其中包含这些关系,但我知道不可能将 OneToMany 关系放在具有原则的映射超类中——这很好。

但是,我仍然不知道如何在没有大量代码冗余的情况下将这些关联起来。我是否将 Address 设为 STI 类型,并使用包含直接与客户关系的“CustomerAddress”子类?有没有办法减少重复次数?

【问题讨论】:

标签: php doctrine-orm


【解决方案1】:

为什么不把你的基础 ContactableEntity 具体化?

编辑:

我刚刚在一个使用 CTI 的项目中做了一些实验。我看不出有任何理由表明相同的策略不适用于 STI。

基本上,我有类似的东西:

/**                                                                                                                                                                                                                                                                                      
 * Base class for orders.  Actual orders are some subclass of order.                                                                                                                                                                                                                     
 *                                                                                                                                                                                                                                                                                       
 * @Entity                                                                                                                                                                                                             
 * @Table(name="OOrder")                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
 * @InheritanceType("JOINED")                                                                                                                                                                                                                                                            
 * @DiscriminatorColumn(name="discr", type="string")                                                                                                                                                                                                                                     
 * @DiscriminatorMap({"CAOrder" = "CAOrder", "AmazonOrder" = "AmazonOrder"})                                                                                                                                                                                                                                                                                                                                                                                      
 */
abstract class Order {
    /**           
     * CSRs can add notes to orders of any type                                                                                                                                                                                                                                                          
     * @OneToMany(targetEntity = "OrderNote", mappedBy = "order", cascade={"all"})                                                                                                                                                                                                         
     * @OrderBy({"created" = "ASC"})                                                                                                                                                                                                                                                         
     */
    protected $notes;

    // ...
}

/**                                                                                                                                                                                                                                                                                      
 * @Entity                                                                                                                                                                                                                                                                               
 */
class AmazonOrder extends Order {

  /**                                                                                                                                                                                                                                                                                    
   * @Column(type="string", length="20")                                                                                                                                                                                                                                                 
   */
  protected $amazonOrderId;

  // ...

}

/**                                                                                                                                                                                                                                                                                      
 * @Entity                                                                                                                                                                                                                                                                               
 */
class OrderNote {
    // ...

    /**                                                                                                                                                                                                                                                                                    
     * @ManyToOne(targetEntity="Order", inversedBy="notes")                                                                                                                                                                                                                                
     */
    protected $order;

    // ...
}

而且它似乎完全按预期工作。我可以得到一个 OrderNote,它的 $order 属性将包含 Order 的一些子类。

使用 STI 是否有一些限制,使您无法做到这一点?如果是这样,我建议搬到 CTI。但我无法想象为什么这不适用于 STI。

【讨论】:

  • 具体化意味着我的所有其他实体都需要使用类表继承。阻止我在 OneToMany 中使用它的原因并不是该类是抽象的,而是它是一个 MappedSuperclass。然而,即使我放弃了 AbstractContactableEntity,我仍然无法从一种“地址”实体到多个不同的其他实体建立多态关系——据我所知。
  • 更新了我的答案 - 我不确定你为什么说你需要使用类表继承。我做了一些测试,并且(使用 CTI),我可以有一个抽象基类,它具有子类继承的一对多关系,而且它似乎工作正常。不明白为什么它也不能与 STI 一起工作 - 但如果不能,我很好奇为什么不能。
  • 感谢您的示例。我的设置与您的类似,但未验证:pastebin.com/q28MUdkk 运行 orm:validate-schema 时收到的错误消息:* The association Address#contactable refers to the inverse side field AbstractContactableEntity#addresses which does not exist. * The referenced column name 'id' does not have a corresponding field with this column name on the class 'AbstractContactableEntity'.
  • 那是因为您使用的是 MappedSuperClass -- 将其改为实体(它仍然可以是抽象类),我怀疑您会很好。
  • 哈哈哈我觉得自己像个白痴。那行得通。谢谢你,好心的先生。
【解决方案2】:

如果可联系实体是抽象的(@MappedSuperclass),您需要使用 Doctrine 2.2+ 提供的 ResolveTargetEntityListener

它基本上允许您通过指定接口而不是具体实体来定义关系。(当您谈到多个“可联系对象”时,也许您想定义/继承多个接口)。例如,您可以在抽象类或具体类中实现接口。最后,您需要在 config.yml 中定义/关联具体类(实体)到相关接口

可以在 Symfony 文档中找到一个示例:http://symfony.com/doc/current/cookbook/doctrine/resolve_target_entity.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-24
    • 2012-08-09
    • 1970-01-01
    相关资源
    最近更新 更多