PHP orm和优化的关系查询


PHP ORMs and optimized relationship queries

我需要一个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

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,包括当前对象,如suspended => false行所示。

我的书可能会帮助你建立你的模式和关系。对象在命名法上应该总是单数,而它们的关系可以是复数(1:1)或单数(1:1)。

天哪,

我已经吃这种狗粮大约2个月了,我喜欢它。红豆。

http://www.redbeanphp.com/

嵌套bean,这是一个对象作为另一个对象的属性的术语。

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

整个文件非常小。与SQL一起工作。我在一个大型项目中使用它,并且喜欢我能快速完成任务的速度。

约翰

Gacela可以通过几种方式自动获取相关信息:

继承关系

在如下示例中:

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表中,因此创建了belongsTo关系,而不是hasMany你的例子反映了什么?

在Gacela中有第三个选项,但是我首先建议您考虑,虽然通常更可取的是主动获取数据,但这确实会影响性能总是主动获取数据,而不是延迟加载数据。正是由于这个原因,默认情况下,Gacela(以及基本上所有其他数据映射器或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);
    }
}