首页 文章

Doctrine继承替换

提问于
浏览
6

我们're developing a very flexible and modular application with Zend Framework 2 and Doctrine 2. In this application there are multiple Doctrine entities, for example let'在模块 Products 中说实体 Product . 该模块 Products 是产品管理的基本/默认模块 .

我们希望能够为客户创建自定义 Products 模块( XProducts ) . 因此,我创建了一个新实体 XProduct (带有一些额外的字段),扩展了 Product .

因此,如果启用了自定义模块,我想使用 XProductProduct ,但从不在一起(在同一个项目中) .

如果我使用@Entity注释两个实体,它会部分工作;例如 findAll 工作正常,但 find 不起作用:创建的SELECT语句包含正确的列,但WHERE子句是错误的 . 例如:

SELECT t1.id AS id2, t1.name AS name3 FROM products t1 WHERE t0.id = ?

我猜 t1 代表 ProductXt0 代表 Product 但我无法弄清楚为什么列是正确的( t1 )但是where子句不是( t0 ) .

我知道Doctrine提供了单表继承来实现继承,但是因此必须有一个DiscriminatorColumn并在base / default实体上定义DiscriminatorMap . 这不适合我们,因为如果我们为客户添加一个新的自定义模块(这不是我们想要的......),我们需要更改我们的基本/默认模块 .

有没有人有解决这个问题的线索?谢谢!

2 回答

  • 7

    我终于解决了这个问题 . 对于所有默认/基类,我创建了一个额外的抽象MappedSuperclass(正如Jurian Sluiman所提到的) . 例如,对于客户的特定 Product 实体,我需要以下内容:

    • AbstractProduct(包含所有默认/基本功能)

    • Product(默认/基类为空并扩展AbstractProduct)

    • XProduct(包含我们客户的额外功能并扩展了AbstractProduct)

    要修复MappedSuperclass上关联的问题,我引用抽象类,例如: @ORM\OneToOne(targetEntity="ProductManagement\Entity\AbstractProduct")

    然后我使用Doctrine的EntityResolver(参见http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/resolve-target-entity-listener.html)将抽象类(或接口)关联映射到实体(取决于配置):

    'entity_resolver' => array(
        'orm_default' => array(
            'resolvers' => array(
                // Note: Use only one
                'ProductManagement\Entity\AbstractProduct' => 'ProductManagement\Entity\Product', // Default
                'ProductManagement\Entity\AbstractProduct' => 'XProductManagement\Entity\XProduct', // For customer X
            )
        )
    )
    

    通过这种方式,我可以使用特定实体覆盖我的客户实体,而无需更改默认/基本模块和实体(这正是我所寻找的) .

  • 3

    我们使用这种模式以及最容易使用的Doctrine(虽然它可以通过许多丑陋的代码使得OOP明智得多) . 以我们的Portfolio模块为例,其中 Portfolio 实例可以占用多个 Item 实例 .

    我们使用 Portfolio 实体,该实体从映射的超类 AbstractPortfolio 扩展 . 如果我们有一个需要特殊字段的客户端,我们创建一个扩展映射超类的 ClientPortfolio ,因此它会正确地重载所有属性 .

    类名是specified in the config,该字符串用于例如factory for the repository . 您永远不会加载 Portfolio 存储库,但是即使您从服务管理器以默认产品组合的名称请求存储库类,也始终加载 ClientPortfolio .

    此方法可以与存储库函数like here一起使用(尽管此类是 Item 而不是 Portfolio 的存储库) . 我不会使用单表继承,因为你不使用彼此之外的多个实体 . 至少,这是我们的情况 .

相关问题