PHP ORM и оптимизированные запросы отношений - PullRequest
3 голосов
/ 29 октября 2011

Мне нужен PHP ORM для хорошей работы с отношениями. Пожалуйста, рассмотрите код ниже в Zend:

$persons = new Persons();
$person = $persons->find(5)->current();
echo 'Name: '.$person->fullname;

$phones = $person->findDependentRowset('Phones');
foreach($phones as $phone)
    echo 'Phone: '.$phone->phonenumber; 

Или код ниже в xPDO:

$person = $xpdo->getObject('Persons', 5);
echo 'Name: '.$person->get('fullname');

$phones = $person->getMany('Phones');
foreach($phones as $phone)
    echo 'Phone: '.$phone->get('phonenumber');

в обоих сценариях ORM выполняет два запроса, как показано ниже:

SELECT * FROM persons WHERE id=5;
SELECT * FROM phones WHERE person=5;

Это означает, что один запрос для основного объекта и один запрос для каждого отношения, но мне нужно использовать ОДИН запрос для основного объекта и его отношений! xPDO может сделать это, как показано ниже:

$person = $xpdo->getObjectGraph('Persons', '{"Phones":{}}', 5);
echo 'Name: '.$person->get('fullname');

foreach($person->Phones as $phone)
    echo 'Phone: '.$phone->get('phonenumber');

, который выполняет этот запрос:

SELECT * FROM persons
LEFT JOIN phones ON phones.person=persons.id
WHERE persons.id=5

Это замечательно, но невозможно установить поля для получения из таблиц! в этом случае xPDO использует "SELECT *" , поэтому, если я получу объект и его 4 отношения, я получу все поля всех этих таблиц!

Так что мне нужно ORM для выполнения запроса ниже, например, выше:

SELECT persons.fullname , phones.phonenumber FROM persons
LEFT JOIN phones ON phones.person=persons.id
WHERE persons.id=5

Doctrine может делать это через DQL, но я думаю, что Doctrine не подходит для личных проектов. Есть ли PHP ORM для этого?

Спасибо AHHP

Ответы [ 3 ]

3 голосов
/ 19 мая 2013

xPDO может это сделать.Вы просто должны скорректировать свое мышление и свой запрос.

Помните, что objectGraph использует имя класса объекта, где в качестве графа и запроса используются отношения в графе.

 $criteria = $this->xpdo->newQuery('prefixClient');
            if (!empty($limit))
                $criteria->limit($limit);
            $criteria->where(array('Child.planid' => $this->getPrimaryKey(),
                                   'Child.active' => true,
                                   'GrandChild.someAttribute' => true,
                                   'GreatGrandChild.someOtherAttribute' => true,
                                   'suspended' => false
                             ));

            $out = $this->xpdo->getCollectionGraph('prefixClient', '{"Child":{"GrandChild":{"GreatGrandChild":{}}}}', $criteria);

Вы устанавливаете WHERE для любого аспекта отношения, включая текущий объект, как показано в строке false => false.

Моя книга может немного помочь вам в установлении вашегосхема и отношения.Объекты всегда должны быть единичными в номенклатуре, тогда как их отношения могут быть множественными (1: M) или единичными (1: 1).

1 голос
/ 29 октября 2011

О человек,

Я ем эту собачью еду около 2 месяцев, и мне это нравится. КРАСНЫЙ БОБ.

http://www.redbeanphp.com/

Вложенные бины - их слова, обозначающие один объект как свойство другого.

http://www.redbeanphp.com/manual/nested_bean

Весь файл довольно маленький. Работает с SQL. Я использую его в масштабном проекте, и мне нравится, как быстро я смогу это сделать.

Джон.

0 голосов
/ 29 октября 2011

Есть несколько способов, которыми Gacela может обрабатывать автоматическую выборку связанной информации:

1) Отношения наследования

В примере, подобном следующему:

CREATE TABLE wizards (
    wizardId INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
    fname VARCHAR(255) NOT NULL,
    lname VARCHAR(255) NOT NULL,
    ROLE ENUM('teacher', 'student') NULL,
    addressId INT UNSIGNED NULL,
    CONSTRAINT fk_address_wizard
    FOREIGN KEY (addressId)
    REFERENCES addresses(addressId)
    ON DELETE SET NULL
) ENGINE = Innodb;

CREATE TABLE students (
    wizardId INT UNSIGNED NOT NULL PRIMARY KEY,
    houseId INT UNSIGNED NOT NULL,
    isDAMembmer BOOL NOT NULL DEFAULT 0,
    CONSTRAINT fk_wizard_student
    FOREIGN KEY (wizardId)
    REFERENCES wizards(wizardId)
    ON DELETE CASCADE,
    CONSTRAINT fk_house_students
    FOREIGN KEY (houseId)
    REFERENCES houses(houseId)
    ON DELETE RESTRICT
) ENGINE = Innodb;

Таблица students имеет тот же первичный ключ, что и таблица wizards, и благодаря определению взаимосвязи внешнего ключа Gacela обнаружит, что students наследует все поля от wizards.

2) Зависимые отношения

Это, вероятно, ближе к тому, что вы ищете:

CREATE TABLE addresses (
    addressId INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    locationName VARCHAR(255) NOT NULL
) ENGINE = Innodb;

CREATE TABLE wizards (
    wizardId INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
    fname VARCHAR(255) NOT NULL,
    lname VARCHAR(255) NOT NULL,
    ROLE ENUM('teacher', 'student') NULL,
    addressId INT UNSIGNED NULL,
    CONSTRAINT fk_address_wizard
        FOREIGN KEY (addressId)
        REFERENCES addresses(addressId)
        ON DELETE SET NULL
) ENGINE = Innodb;

Однако этот пример все еще немного отличается от вашего примера, поскольку addressId находится в wizards таблица, таким образом, создавая отношение ownTo, а не hasMany, что отражает ваш пример.

Существует третий вариант, доступный в Gacela, однако я хотел бы сначала предположить, что вы считаете, что, хотя зачастую предпочтительнее получать данные с нетерпением, существуют реальные последствия для производительности при всегда извлеченной загрузке, а не при отложенной загрузке данных.Именно по этой причине Gacela (и в основном любой другой Data Mapper или ORM) по умолчанию не с готовностью извлекает данные из отношений hasMany.Тем не менее, вы можете написать что-то вроде следующего:

class Mapper extends \Gacela\Mapper 
{

    public function find($id)
    {
        $query = $this->_source()->query();

        $query->from('persons', array('fullName'))
            ->join('phones', 'phones.person=persons.id', array('phonenumber'), 'left')
            ->where('persons.id = :id', array(':id' => $id);

        $data = $this->_source->query($query);

        return $this->_load($data);
    }
}
...