PHP学说1.2 ORM——类表继承的多态查询

发布于 2024-09-09 02:13:25 字数 886 浏览 7 评论 0原文

我正在尝试 PHP 的 Doctrine ORM (v1.2)。我定义了一个类“liquor”,有两个子类“gin”和“whiskey”。我使用具体继承(大多数文献中的类表继承)将类映射到三个单独的数据库表。

我正在尝试执行以下操作:

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

最初,我期望 $liquors 是一个包含所有酒类的 Doctrine_Collection,无论它们是威士忌还是杜松子酒。但是,当我执行代码时,尽管威士忌和杜松子酒数据库表中有几行,但我得到一个空集合。根据生成的 SQL,我明白了原因:ORM 正在查询“liquor”表,而不是存储实际数据的威士忌/杜松子酒表。

请注意,当我将继承类型切换为列聚合(简单表继承)时,代码完美运行。

获得包含所有酒类的 Doctrine_Collection 的最佳方式是什么?

更新

经过更多研究后,我似乎期望 Doctrine 在幕后执行 SQL UNION 操作,以合并来自“威士忌”和“的结果集”杜松子酒”桌子。

这称为多态查询

根据此票据,此功能在 Doctrine 1.x 中不可用。它注定要发布 2.0 版本。 (另请参阅 Doctrine 2.0 文档

那么根据这些信息,解决这一缺陷的最干净、最有效的方法是什么?切换到单表继承?执行两个 DQL 查询并手动合并生成的 Doctrine_Collections?

I'm experimenting with the Doctrine ORM (v1.2) for PHP. 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. 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.

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?

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.

This is known as a polymorphic query.

According to this ticket, this functionality is not available in Doctrine 1.x. It is destined for the 2.0 release. (also see Doctrine 2.0 docs for CTI).

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

凉薄对峙 2024-09-16 02:13:25

目前Doctrine唯一稳定且有用的继承模式是column_aggregation。我在不同的项目中尝试过其他的。使用column_aggregation,您可以模仿多态查询。
一般来说,继承在 Doctrine (1.x) 中存在一些问题。在 2.x 中,这种情况将会改变,因此我们将来可能有更好的选择。

the only stable and useful inheritence mode of Doctrine for the moment is column_aggregation. I have tried the others in different projects. With column_aggregation you can imitate polymorphic queries.
Inheritance in general is something that is a bit buggy in Doctrine (1.x). With 2.x this will change, so we may have better options in the future.

忆沫 2024-09-16 02:13:25

我写了一个 ORM 的开头(尚未准备好用于生产),它可以完全满足您不久前所寻找的功能。这样我就可以得到概念证明。我所有的研究确实表明您以某种方式混合了代码和数据(酒表中的子类信息)。

因此,您可能要做的就是在酒类/表类上编写一个方法来查询它自己的表。 不必对酒类中的所有子类进行硬编码的最好方法是有一列包含子类的类名。

如何传播细节完全取决于您。我认为最标准化的(如果我在这里错了,任何人都可以纠正我)方法是将出现在酒类表中的所有字段存储起来。然后,对于每个子类,都有一个表来存储属于子类类型的特定数据。
这是您混合代码和数据的点,因为您的代码正在读取酒类表以获取子类的名称以执行联接。

我会使用汽车和对于我的例子来说,它们之间有一些最小但微不足道的差异:

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')

从这里开始有各种各样的变化,例如将所有酒类数据存储在子类表中,并且仅在酒类表中存储引用和子类名称。我最不喜欢这个,因为如果您聚合公共数据,它可以使您不必查询每个子类表的公共字段。

希望这有帮助!

I wrote the (not production ready) beginnings of an ORM that would do exactly what you're looking for a while back. 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!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文