Я экспериментирую с Доктриной ORM (v1.2) для PHP. Я определил класс "алкоголь" с двумя дочерними классами "джин" и "виски". Я использую конкретное наследование (наследование таблицы класса в большей части литературы) для отображения классов на три отдельных таблицы базы данных.
Я пытаюсь выполнить следующее:
$liquor_table = Doctrine_Core::getTable('liquor');
$liquors = $liquor_table->findAll();
Первоначально, я ожидал, что $liquors будет Doctrine_Collection, содержащим все спиртные напитки, ли они быть виски или джином. Но когда я выполняю код, я получаю пустой набор, несмотря на наличие нескольких строк в таблицах базы данных джина и виски. На основе сгенерированного SQL я понимаю почему: ORM запрашивает таблицу "алкоголя" а не таблицы виски/джина, где фактические данные хранятся.
Обратите внимание, что код работает отлично, когда я переключаю тип наследования на агрегирование столбца (простое наследование таблицы).
Что лучший способ состоит в том, чтобы получить Doctrine_Collection, содержащий все спиртные напитки?
Обновление
Еще после некоторого исследования похоже, что я ожидаю, что Доктрина выполнит SQL UNION
операция негласно для объединения наборов результатов от таблиц "виски" и "джина".
Это известно как полиморфный запрос.
Согласно этому билету, эта функциональность не доступна в Доктрине 1.x. Это предназначено для этих 2,0 выпусков. (также см. документы Доктрины 2.0 для CTI).
Таким образом в свете этой информации, каков был бы самый чистый, самый эффективный способ работать вокруг этого дефицита? Переключиться на единственное наследование таблицы? Выполнить два запроса DQL и вручную объединить получающийся Doctrine_Collections?
единственным стабильным и полезным режимом наследования Doctrine на данный момент является column_aggregation. Остальные я пробовал в разных проектах. С помощью column_aggregation можно имитировать полиморфные запросы. Наследование в целом - это то, что в Doctrine (1.x) немного глючит. В версии 2.x это изменится, так что в будущем у нас могут появиться лучшие возможности.
Я написал (не готово к производству) начало 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')
Здесь и впредь есть всевозможные вариации, такие как сохранение всех данных о классе спиртных напитков в таблице подклассов и сохранение только ссылок и подклассов имена в таблице спиртных напитков. Мне это нравится меньше всего, потому что, если вы собираете общие данные, это избавляет вас от необходимости запрашивать общие поля в каждой таблице подкласса.
Надеюсь, это поможет!