Как заполнить аддитивное поле через JOIN с Doctrine

Предположим, у меня есть объект с отношением ManyToOne (с EXTRA_LAZY) и, очевидно, столбец соединения.

eg. Article (main entity) -> Author (external entity)

предположим, я добавляю в статью поле author_name, которое НЕ отображается в ORM, и что в определенных контекстах это поле должно содержать значение article->author->name (обычно оно может оставаться нулевым).

Когда я запрашиваю список статей, я хотел бы автоматически заполнить этот article-author_name без реализации геттера, который выполняет выбор для каждого элемента результата запроса. Я хотел бы, чтобы Doctrine извлекала и гидратировала это значение с помощью простого JOIN в исходном запросе...

Я не хочу устанавливать режим извлечения EAGER для повышения производительности, так как в моем проекте Author — это действительно сложный объект.

Это возможно?

Спасибо


person Alex    schedule 02.03.2017    source источник
comment
Сегодня я проверил все аннотации Doctrine и не нашел ни одной, которая позволила бы вам это сделать.   -  person Ihor Burlachenko    schedule 09.03.2017


Ответы (1)


Наверное, я нашел решение. Не знаю, лучший ли это способ, но он работает.

Я добавил в основной класс геттер поля

public getAuthorName() {
  return $this->author->name
}

в моем контексте этот геттер будет вызываться сериализатором только при определенных условиях.

В моем коде репозитория у меня есть специальный метод (который я реорганизовал, чтобы любой метод мог неявно вызывать его) для наложения заполнения поля «Статья->автор» при запросе. Этот метод просто использует конструктор запросов, чтобы добавить LEFT JOIN в класс Author и временно установить FetchMode в EAGER для Article->author.

В конце концов, простой метод репозитория может быть таким

public findAllWithCustomHydration() {
    $qb = $this->createQueryBuilder('obj');
    $qb->leftJoin("obj.author", "a")
       -> addSelect("a"); //add a left join and a select so the query automatically retrive all needed values to populate Article and Author entities
    //you can chain left join for nested entities like the following
    //->leftJoin("a.address", "a_address")
    //-> addSelect("a_address");


    $q = $qb->getQuery()
              ->setFetchMode(Article::class, "author", ClassMetadata::FETCH_EAGER);
   //setFetchMode + EAGER tells Doctrine to prepopulate the entites NOW and not when the getter of  $article->author is called. 
   //I don't think that line is strictly required because Doctrine could populate it at later time from the same query result or maybe doctrine automatically set the field as EAGER fetch when a LEFT JOIN is included in the query, but i've not yet tested my code without this line.

    return $q->getResult();
}

Минус в том, что вам нужно настраивать каждый запрос или лучше использовать DQL/SQL/QueryBuilder для каждого метода репо, но с хорошим рефакторингом, для простых случаев включения вы можете написать общий метод, который внедряет это соединение в массив field_name основа.

Надеюсь, что это поможет и добавить свой ответ, если вы найдете лучший способ.

PS. Я написал приведенный выше код на лету, потому что сейчас я не на своем ноутбуке, надеюсь, он сработает при первом выполнении.

person Alex    schedule 12.03.2017