如何为带entity_type字段的Url实体配置Doctrine关联关系?
在Doctrine中实现基于entity_type的多态关联方案
针对你这种Url实体通过entity_id和entity_type关联Article/Page的场景,Doctrine原生支持多态关联配置,以下是两种可行方案:
方案一:基于抽象父类的继承映射
- 定义抽象父类,统一管理公共字段并配置继承规则:
/** * @Entity * @InheritanceType("JOINED") * @DiscriminatorColumn(name="entity_type", type="string") * @DiscriminatorMap({"article" = "Article", "page" = "Page"}) */ abstract class AbstractContent { /** * @Id @GeneratedValue @Column(type="integer") */ protected $id; /** * @Column(type="string") */ protected $title; /** * @Column(type="text") */ protected $text; }
- 让Article和Page继承该抽象类:
/** * @Entity */ class Article extends AbstractContent { // 可添加Article独有的字段 } /** * @Entity */ class Page extends AbstractContent { // 可添加Page独有的字段 }
- 在Url实体中配置单向OneToOne关联:
/** * @Entity */ class Url { /** * @Id @GeneratedValue @Column(type="integer") */ private $id; /** * @Column(type="string") */ private $url; /** * @OneToOne(targetEntity="AbstractContent") * @JoinColumn(name="entity_id", referencedColumnName="id") */ private $content; // Getter & Setter }
- 可选:在抽象父类中添加反向关联,实现双向查询:
// 在AbstractContent中添加 /** * @OneToOne(targetEntity="Url", mappedBy="content") */ protected $url;
此方案利用Doctrine原生继承机制自动维护entity_type字段,无需手动处理类型标识。
方案二:基于接口的多态关联(不修改原有实体结构)
如果不想调整Article和Page的继承关系,可通过接口配合鉴别器映射实现:
- 创建公共接口:
interface UrlOwnableInterface { public function getUrl(): ?Url; public function setUrl(?Url $url): void; }
- 让Article和Page实现接口并添加反向关联:
/** * @Entity */ class Article implements UrlOwnableInterface { // 原有字段... /** * @OneToOne(targetEntity="Url", mappedBy="owner") */ private $url; public function getUrl(): ?Url { return $this->url; } public function setUrl(?Url $url): void { $this->url = $url; } } // Page类做同样的实现
- 在Url实体中配置多态关联,指定鉴别器映射:
/** * @Entity */ class Url { // 原有字段... /** * @OneToOne(targetEntity="UrlOwnableInterface") * @JoinColumn(name="entity_id", referencedColumnName="id") * @DiscriminatorColumn(name="entity_type", type="string") * @DiscriminatorMap({ * "article" = "Article", * "page" = "Page" * }) */ private $owner; // Getter & Setter }
此方案无需修改原有实体的继承结构,直接通过接口绑定,手动指定entity_type与实体类的映射关系。
注意事项
- 两种方案都能让Doctrine自动处理关联的持久化和查询,比如查询Url时可直接获取关联的Article/Page对象,无需手动拼接SQL。
- 接口方案要求Doctrine版本在2.4及以上,支持接口作为关联目标。
- 若不需要双向关联,可去掉实体中的
inversedBy和反向关联字段,仅保留Url中的单向关联。
内容的提问来源于stack exchange,提问作者Daimos
相关产品推荐
相关产品推荐

