目前我们正在使用Zend Framework 2和Doctrine 2开发一个非常灵活的模块化应用程序。在这个应用程序中有多个Doctrine实体,例如假设模块Product
中的实体Products
。此模块Products
是产品管理的基础/默认模块。
我们希望能够为客户(Products
)创建自定义XProducts
模块。因此,我创建了一个新实体XProduct
(带有一些额外字段),扩展了Product
。
因此,如果启用了自定义模块,我想使用XProduct
和其他Product
,但不要在一起(在同一个项目中)。
如果我使用@Entity注释两个实体,它会部分工作;例如findAll
工作正常,但find
不起作用:创建的SELECT语句包含正确的列,但WHERE子句是错误的。例如:
SELECT t1.id AS id2, t1.name AS name3 FROM products t1 WHERE t0.id = ?
我猜t1
代表ProductX
而t0
代表Product
,但我无法弄清楚为什么列正确(t1
)但是where子句不是(t0
)。
我知道Doctrine提供单表继承来实现继承,但是因此必须有一个DiscriminatorColumn并在base / default实体上定义DiscriminatorMap。这不适合我们,因为如果我们为客户添加一个新的自定义模块(这不是我们想要的......),我们需要更改我们的基本/默认模块。
有没有人有解决这个问题的线索?谢谢!
答案 0 :(得分:7)
我终于解决了这个问题。对于所有默认/基类,我创建了一个额外的抽象MappedSuperclass(正如Jurian Sluiman所提到的)。例如,对于客户的特定Product
实体,我需要以下内容:
要修复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
)
)
)
通过这种方式,我可以使用特定实体覆盖我的客户,而无需更改默认/基本模块和实体(这正是我所寻找的)。
答案 1 :(得分:3)
我们使用这种模式以及最容易使用的Doctrine(尽管可以通过大量丑陋的代码使得OOP明智得多)。以我们的Portfolio模块为例,Portfolio
个实例可以占用多个Item
个实例。
我们使用从映射的超类Portfolio
扩展的AbstractPortfolio
实体。如果我们有一个需要特殊字段的客户端,我们创建一个ClientPortfolio
来扩展映射的超类,因此它会正确地重载所有属性。
班级名称为specified in the config,该字符串用于例如factory for the repository。您永远不会加载Portfolio
存储库,但即使您从服务管理器以默认产品组合的名称请求存储库类,也始终加载ClientPortfolio
。
此方法可以与存储库函数like here一起使用(尽管此类是Item
而不是Portfolio
的存储库)。我不会使用单表继承,因为你不使用彼此之外的多个实体。至少,这是我们的情况。