Доктрина PHP 1.2 ORM - полиморфные запросы с наследованием таблицы классов

Я экспериментирую с Doctrine ORM (v1.2) для PHP. Я определил класс "ликер", с двумя дочерними классами "джин" и "виски". Я использую конкретное наследование (наследование таблицы классов в большинстве литературы) для сопоставления классов с тремя отдельными таблицами базы данных.

Я пытаюсь выполнить следующее:

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

Вначале я ожидал, что $ликеры станут Доктриной_Коллекцией, содержащей все ликеры, будь то виски или джин. Но когда я выполняю код, я получаю пустую коллекцию, несмотря на наличие нескольких строк в таблицах базы данных виски и джина. Основываясь на сгенерированном SQL, я понимаю, почему: ORM запрашивает таблицу "ликер", а не таблицы виски/джина, где хранятся фактические данные.

Обратите внимание, что код отлично работает, когда я переключаю тип наследования на агрегацию столбцов (простое наследование таблицы).

Какой лучший способ получить Doctrine_Collection, содержащий все ликеры?

Обновление

После нескольких исследований, похоже, я ожидаю, что Doctrine выполнит операцию SQL UNION за кулисами, чтобы комбинировать наборы результатов от таблиц "виски" и "джина".

Это называется полиморфным запросом.

Согласно этот билет, эта функция недоступна в Doctrine 1.x. Он предназначен для выпуска 2.0. (также см. Doctrine 2.0 docs для CTI).

Итак, в свете этой информации, какой будет самый чистый и эффективный способ обойти этот недостаток? Переключиться на однонаправленное наследование? Выполните два запроса DQL и вручную объедините полученные Doctrine_Collections?

Ответ 1

единственным стабильным и полезным режимом наследования доктрины на данный момент является column_aggregation. Я пробовал других в разных проектах. С помощью column_aggregation вы можете имитировать полиморфные запросы. Наследование вообще - это что-то, что немного ошибочно в Doctrine (1.x). С 2.x это изменится, поэтому у нас могут быть лучшие варианты в будущем.

Ответ 2

Я написал (не готовую) начало 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')

Здесь есть всевозможные варианты, такие как хранение всех данных класса ликера в таблице подкласса и сохранение только ссылок и подкласса в таблице ликера. Мне это нравится меньше всего, потому что, если вы объединяете общие данные, это избавляет вас от необходимости запрашивать каждую таблицу подкласса для общих полей.

Надеюсь, это поможет!