简体   繁体   English

PHP doctrine 1.2 ORM - 具有类表继承的多态查询

[英]PHP doctrine 1.2 ORM - polymorphic queries with class table inheritance

I'm experimenting with the Doctrine ORM (v1.2) for PHP. 我正在试验PHP的Doctrine ORM(v1.2)。 I have defined a class "liquor", with two child classes "gin" and "whiskey". 我已经定义了一个班级“酒”,有两个孩子类“杜松子酒”和“威士忌”。 I am using concrete inheritance (class table inheritance in most literature) to map the classes to three seperate database tables. 我使用具体的继承(大多数文献中的类表继承)将类映射到三个单独的数据库表。

I am attempting to execute the following: 我试图执行以下操作:

$liquor_table = Doctrine_Core::getTable('liquor');
$liquors = $liquor_table->findAll();

Initially, I expected $liquors to be a Doctrine_Collection containing all liquors, whether they be whiskey or gin. 最初,我预计$ liquors是一个包含所有酒类的Doctrine_Collection,无论它们是威士忌还是杜松子酒。 But when I execute the code, I get a empty collection, despite having several rows in the whiskey and gin database tables. 但是当我执行代码时,我得到一个空集合,尽管在威士忌和杜松子酒数据库表中有几行。 Based on the generated SQL, I understand why: the ORM is querying the "liquor" table, and not the whiskey/gin tables where the actual data is stored. 基于生成的SQL,我理解为什么:ORM查询“酒”表,而不是存储实际数据的威士忌/杜松子酒表。

Note that the code works perfectly when I switch the inheritance type to column aggregation (simple table inheritance). 请注意,当我将继承类型切换到列聚合(简单表继承)时,代码可以正常工作。

What's the best way to obtain a Doctrine_Collection containing all liquors? 获取包含所有酒的Doctrine_Collection的最佳方法是什么?

Update 更新

After some more research, it looks like I'm expecting Doctrine to be performing a SQL UNION operation behind the scenes to combine the result sets from the "whiskey" and "gin" tables. 经过一些研究后,看起来我期待Doctrine在幕后执行SQL UNION操作,以组合“威士忌”和“杜松子酒”表的结果集。

This is known as a polymorphic query . 这称为多态查询

According to this ticket , this functionality is not available in Doctrine 1.x. 根据此票证 ,Doctrine 1.x中不提供此功能。 It is destined for the 2.0 release. 它注定要发布2.0版本。 (also see Doctrine 2.0 docs for CTI ). (另见CTI的 Doctrine 2.0文档)。

So in light of this information, what would be the cleanest, most efficient way to work around this deficiency? 因此,根据这些信息,解决这一缺陷的最简洁,最有效的方法是什么? Switch to single table inheritance? 切换到单表继承? Perform two DQL queries and manually merge the resulting Doctrine_Collections? 执行两个DQL查询并手动合并生成的Doctrine_Collections?

the only stable and useful inheritence mode of Doctrine for the moment is column_aggregation. 目前唯一稳定而有用的Doctrine继承模式是column_aggregation。 I have tried the others in different projects. 我在不同的项目中尝试过其他人。 With column_aggregation you can imitate polymorphic queries. 使用column_aggregation,您可以模仿多态查询。 Inheritance in general is something that is a bit buggy in Doctrine (1.x). 一般来说,继承在Doctrine(1.x)中有点麻烦。 With 2.x this will change, so we may have better options in the future. 2.x会改变,所以我们将来可能有更好的选择。

I wrote the (not production ready) beginnings of an ORM that would do exactly what you're looking for a while back. 我写了一个(不是生产准备好的)ORM的开头,它可以完成你正在寻找的东西。 Just so that I could have a proof of concept. 这样我才能有一个概念证明。 All my studies did yield that you're in some way mixing code and data (subclass information in the liquor table). 我的所有研究都确实让你以某种方式混合代码和数据(酒表中的子类信息)。

So what you might do is write a method on your liquor class/table class that queries it's own table. 所以你可能会做的是在你的酒类/表类中编写一个查询它自己的表的方法。 The best way to get away with not having to hard-code all the subclasses in your liquor class is to have a column which contains the class name of the subclass in it. 不必对您的酒类中的所有子类进行硬编码的最佳方法是使用一个包含其子类的类名的列。

How you spread the details around is entirely up to you. 你如何传播细节完全取决于你。 I think the most normalized (and anyone can correct me if I'm wrong here) way to do it is to store all fields that appear in your liquor class in the liquor table. 我认为最正常化(任何人都可以纠正我,如果我在这里错了)这样做的方法是将酒类中出现的所有字段存储在酒类表中。 Then, for each subclass, have a table that stores the specific data that pertains to the subclass type. 然后,对于每个子类,都有一个表,用于存储与子类类型相关的特定数据。 Which is the point at which you are mixing code and data because your code is reading the liquor table to get the name of the subclass to perform a join. 在哪个位置混合代码和数据是因为您的代码正在读取酒表以获取子类的名称来执行连接。

I'll use cars & bikes and some minimal, yet trivial differences between them for my example: 我将使用汽车和自行车以及它们之间的一些微小但微不足道的差异为我的例子:

Ride
----
id
name
type

(1, 'Sebring', 'Car')
(2, 'My Bike', 'Bicycle')

Bicycle
-------
id
bike_chain_length

(2, '2 feet')

Car
---
id
engine_size

(1, '6 cylinders')

There's all kinds of variations from here forward like storing all liquor class data in the subclass table and only storing references and subclass names in the liquor table. 从这里开始有各种各样的变化,比如在子类表中存储所有的酒类数据,并且只在白酒表中存储引用和子类名称。 I like this the least though because if you are aggregating the common data, it saves you from having to query every subclass table for the common fields. 我最喜欢这个,但是如果你正在聚合公共数据,它将使你不必查询公共字段的每个子类表。

Hope this helps! 希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM