Извлечение данных из ассоциаций в Doctrine 2 и Zend Framework - PullRequest
3 голосов
/ 12 января 2012

В моем проекте определена простая структура сущностей:

Страна> Регион> Провинция> Город

определено так:

class Town
{
    /**
     * @Id @Column(type="integer")
     * @GeneratedValue(strategy="AUTO")
     */
    private $id;

    /** @Column(type="string", length=30,unique=FALSE) */
    private $townname;

    /** @Column(type="boolean") */
    private $active;

    // so that we know when a user has added a town
    /** @Column(type="boolean") */
    private $verified;


    /**
     * @ManyToOne(targetEntity="Province")
     * @JoinColumn(name="provinces_id", referencedColumnName="id",nullable=FALSE)
     */
    private $provinces_id;

и т.д.

OK. Вы поняли идею.

Теперь, если у пользователя есть город (много к одному), я бы хотел узнать провинцию, регион и страну для этого пользователя. Я мог бы создать метод репозитория для городского объекта, который предоставляет эти данные с использованием SQL или DQL. Что-то вроде:

SELECT `users`.`towns_id`,`towns`.`provinces_id`,`regions`.`countries_id`,`provinces`.`regions_id` FROM users , `regions`
LEFT JOIN `towns` ON `users`.`towns_id` = `towns`.`id` 
LEFT JOIN `provinces` ON `towns`.`provinces_id` = `provinces`.`id` 

Но это кажется неправильным, тем более что доктрина уже «знает» об отношениях между городами, провинциями, регионами и странами.

Есть ли более простой способ сделать это?

Ответы [ 2 ]

2 голосов
/ 14 мая 2012

Все зависит от того, как вы хотите получить эти объекты из базы данных.Может быть лучше использовать DQL, если вы хотите минимизировать операторы SQL, отправляемые против БД.

Так что для вашей ситуации я бы добавил несколько DQL:

$dql = 'SELECT u, t, p, r, c FROM User u JOIN u.towns_id t JOIN t.provinces_id p JOIN p.regions_id r JOIN r.countries_id c WHERE u.firstname = ?1';
$user = $this->em->createQuery($dql)->setParameter(1, 'test')->getResults();

$country = $user->getTowns_id()->getProvinces_id()->getRegions_id()->getCountries_id()->getCountryname();

DQL работает с классами и их свойствами( НЕ в столбцах таблицы).Поэтому, написав DQL, вы фактически используете то, что доктрина «знает» об ассоциациях ваших сущностей.

Приведенный выше набор результатов эквивалентен, когда используется только одна строка:

$country = $user->getTowns_id()->getProvinces_id()->getRegions_id()->getCountries_id()->getCountryname();

Но вы получаете те же результаты с одним запросом SQL SELECT (с JOINS под капотом) вместо 3 SELECTS.И это будет работать быстрее.

0 голосов
/ 13 января 2012

В итоге я сделал это так:

Я сделал двунаправленные ассоциации (хотя это, вероятно, и не нужно):

// in towns entity
    /**
         * @ManyToOne(targetEntity="Province", inversedBy="towns")
         * @JoinColumn(name="provinces_id", referencedColumnName="id",nullable=FALSE)
         */
        private $provinces_id;



// in provinces entity

/**
     * @OneToMany(targetEntity="Town", mappedBy="towns")
     */
    private $towns;

    public function __construct() {
        $this->towns = new ArrayCollection();
        $this->active = true;
    }

    public function getTowns() {
        return $this->towns;
    }

Вы можете просто сослаться на страну пользователя, как это:

$user = new \Entities\User;
$user = $this->em->getRepository('Entities\User')->findOneByFirstname('test');

$country=$user->getTowns_id()->getProvinces_id()->getRegions_id()->getCountries_id()->getCountryname();
...