За кулисами: как «думает» ORM? - PullRequest
5 голосов
/ 21 июля 2009

Мне интересны некоторые разработки Rails ActiveRecord, Doctrine для PHP (и аналогичных ORM).

  • Как ORM удается реализовать такие функции, как цепочечные средства доступа, и насколько они обычно работают?
  • Как ORM создает запросы внутренне?
  • Как ORM управляет запросами, поддерживая произвольный характер всего, что от него ожидается?

Очевидно, что это академический вопрос, но приветствуются все виды ответов!

(Мой язык выбора - OO PHP5.3!)

Ответы [ 4 ]

3 голосов
/ 21 июля 2009

Цепные вызовы методов ортогональны вопросу ORM, они используются повсеместно в ООП. Способный к цепочке метод просто возвращает ссылку на текущий объект, позволяя вызвать возвращаемое значение. В PHP

class A {
    public function b() {
        ...
        return $this;
    }

    public function c($param) {
        ...
        return $this;
    }       
}


$foo = new A();
$foo->b()->c('one');
// chaining is equivilant to
// $foo = $foo->b();
// $foo = $foo->c();

Что касается того, как строятся запросы, есть два метода. В ActiveRecord, подобном ORM, есть код, который проверяет метаданные базы данных. Большинство баз данных имеют какие-то SQL или SQL-подобные команды для просмотра этих метаданных. (MySQL DESCRIBE TABLE, таблица Oracle USER_TAB_COLUMNS и т. Д.)

В некоторых ORM вы описываете таблицы своей базы данных на нейтральном языке, таком как YAML. Другие могут вывести структуру базы данных из того, как вы создавали свои объектные модели (я хочу сказать, что Django делает это, но я давно на это смотрел). Наконец, существует гибридный подход, в котором используется любой из двух предыдущих методов, но предоставляется отдельный инструмент для автоматической генерации YAML / etc. или файлы классов.

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

Что касается вашего последнего вопроса,

Как ORM управляет запросами во время поддерживая произвольный характер всех что от этого ожидается?

Я бы сказал, что ответ "не очень хорошо". Когда вы выходите за пределы метафоры «один стол» и «один объект», у каждого ORM свой подход к философии относительно того, как следует использовать запросы SQL для моделирования объектов. В абстрактном смысле это так же просто, как добавить новые методы, которые создают запросы на основе предположений ORM (то есть метод "findManyToManyRowset" Zend_Db_Table)

2 голосов
/ 07 марта 2010

Как ORM удается реализовать такие функции, как цепочечные средства доступа, и насколько они обычно работают?

Кажется, никто не ответил на это. Я могу быстро описать, как Doctrine делает это в PHP.

В Doctrine ни одно из полей, которые вы видите в объектной модели, фактически не определено для этого класса. Итак, в вашем примере, $ car-> owners, в классе $ car не определено действительное поле с именем 'owners'.

Вместо этого ORM использует магические методы, такие как __ get и __set . Поэтому, когда вы используете выражение типа $ car-> color, PHP внутренне вызывает Doctrine_Record #__ get ('color').

На данный момент ORM может удовлетворить это в любом случае необходимо. Здесь много возможных дизайнов. Например, он может хранить эти значения в массиве с именем $ _values, а затем возвращать $ this -> _ values ​​['color']. В частности, доктрина отслеживает не только значения для каждой записи, но и ее статус относительно постоянства в базе данных.

Один пример этого, который не интуитивен, - это отношения Учения. Когда вы получаете ссылку на $ car, она связывается с таблицей People, которая называется 'owners'. Таким образом, данные для $ car-> владельцев фактически хранятся в отдельной таблице от данных для самого $ car. Таким образом, у ORM есть два варианта:

  1. Каждый раз, когда вы загружаете $ user, ORM автоматически объединяет все связанные таблицы и заполняет эту информацию в объекте. Теперь, когда вы делаете $ car-> owners, эти данные уже есть. Однако этот метод медленный, потому что у объектов может быть много связей, и сами эти отношения могут иметь отношения. Таким образом, вы будете добавлять много объединений и не обязательно даже использовать эту информацию.
  2. Каждый раз, когда вы загружаете $ user, ORM замечает, какие поля загружаются из таблицы User, и заполняет их, но все поля, которые загружаются из связанных таблиц, не загружаются. Вместо этого к этим полям прикрепляются некоторые метаданные, чтобы пометить их как «не загруженные, но доступные». Теперь, когда вы пишете выражение $ car-> owners, ORM видит, что отношение «владельцы» не было загружено, и выдает отдельный запрос, чтобы получить эту информацию, добавить ее в объект и затем вернуть эти данные. Все это происходит прозрачно, и вам не нужно это осознавать.

Конечно, Doctrine использует # 2, поскольку # 1 становится громоздким для любой реальной производственной площадки с умеренной сложностью. Но это также имеет побочные эффекты. Если вы используете несколько отношений на $ car, то Doctrine загрузит каждое из них по отдельности, когда вы получите к нему доступ. Таким образом, вы выполняете 5-6 запросов, когда, возможно, требуется только 1.

Doctrine позволяет оптимизировать эту ситуацию с помощью Doctrine Query Language. Вы говорите DQL, что хотите загрузить автомобильный объект, а также присоедините его к его владельцам, производителю, заголовкам, залоговым удержаниям и т. Д., И он загрузит все эти данные в объекты.

Уф! Долгий ответ. В основном, однако, вы получили в основе "Какова цель ORM?" и "Почему мы должны использовать один?" ORM позволяет нам продолжать мыслить в объектном режиме в большинстве случаев, но абстракция не идеальна, и утечки в абстракции имеют тенденцию к снижению производительности.

1 голос
/ 21 августа 2009

Я создал презентацию на тему создания PHP DataMapper, которая может быть вам интересна. Он был записан на видео в Коворкинг-кооперативе Оклахома-Сити, когда я представил его там для группы пользователей PHP:

Видео: http://blip.tv/file/2249586/

Презентационные слайды: http://www.slideshare.net/vlucas/building-data-mapper-php5-presentation

Презентация была в основном ранней концепцией phpDataMapper , хотя с тех пор многое изменилось

Надеюсь, они помогут вам немного лучше понять внутреннюю работу ORM.

0 голосов
/ 21 июля 2009

Связанные средства доступа на самом деле не имеют большого значения: вы return $this из метода установки. Бум, готово, работает на любом количестве уровней.

...