Как 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 есть два варианта:
- Каждый раз, когда вы загружаете $ user, ORM автоматически объединяет все связанные таблицы и заполняет эту информацию в объекте. Теперь, когда вы делаете $ car-> owners, эти данные уже есть. Однако этот метод медленный, потому что у объектов может быть много связей, и сами эти отношения могут иметь отношения. Таким образом, вы будете добавлять много объединений и не обязательно даже использовать эту информацию.
- Каждый раз, когда вы загружаете $ user, ORM замечает, какие поля загружаются из таблицы User, и заполняет их, но все поля, которые загружаются из связанных таблиц, не загружаются. Вместо этого к этим полям прикрепляются некоторые метаданные, чтобы пометить их как «не загруженные, но доступные». Теперь, когда вы пишете выражение $ car-> owners, ORM видит, что отношение «владельцы» не было загружено, и выдает отдельный запрос, чтобы получить эту информацию, добавить ее в объект и затем вернуть эти данные. Все это происходит прозрачно, и вам не нужно это осознавать.
Конечно, Doctrine использует # 2, поскольку # 1 становится громоздким для любой реальной производственной площадки с умеренной сложностью. Но это также имеет побочные эффекты. Если вы используете несколько отношений на $ car, то Doctrine загрузит каждое из них по отдельности, когда вы получите к нему доступ. Таким образом, вы выполняете 5-6 запросов, когда, возможно, требуется только 1.
Doctrine позволяет оптимизировать эту ситуацию с помощью Doctrine Query Language. Вы говорите DQL, что хотите загрузить автомобильный объект, а также присоедините его к его владельцам, производителю, заголовкам, залоговым удержаниям и т. Д., И он загрузит все эти данные в объекты.
Уф! Долгий ответ. В основном, однако, вы получили в основе "Какова цель ORM?" и "Почему мы должны использовать один?" ORM позволяет нам продолжать мыслить в объектном режиме в большинстве случаев, но абстракция не идеальна, и утечки в абстракции имеют тенденцию к снижению производительности.