PHP доктрина 1.2 ORM - полиморфные запросы с наследованием таблиц классов - PullRequest
15 голосов
/ 09 июля 2010

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

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

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

Изначально я ожидал, что $ liquors будет коллекцией Doctrine_Collection, содержащей все ликеры, будь то виски или джин. Но когда я выполняю код, я получаю пустую коллекцию, несмотря на наличие нескольких строк в таблицах базы данных виски и джина. Основываясь на сгенерированном SQL, я понимаю, почему: ORM запрашивает таблицу «ликера», а не таблицы виски / джина, где хранятся фактические данные.

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

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

Обновление

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

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

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

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

Ответы [ 2 ]

3 голосов
/ 12 августа 2010

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

0 голосов
/ 09 августа 2010

Я написал (не готовый к производству) начало 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')

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

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

...