Спустя годы, но может помочь.
Да]
Если вам нужно / хотите / нужно, вы можете использовать Querybuilder для выполнения запроса на обновление , имеющего оператор sub select, вместо непосредственного использования нижележащего уровня соединения.
Идея в том, чтобы использовать QueryBuilder дважды.
- Построение оператора select для вычисления нового значения.
- Создайте фактический запрос на обновление для отправки в базу данных, в которой вы будете вводить первый выбранный DQL, как вы и ожидали, для выдачи одного запроса к базе данных.
Пример]
Предоставлено приложение, в котором пользователи могут продавать объекты. Каждая сделка включает в себя покупателя и продавца. После завершения транзакции продавцы и покупатели могут оставить отзыв о том, как прошла сделка с их контрагентом.
Вам может потребоваться таблица Пользователь , таблица Просмотр и таблица Транзакция .
Таблица User содержит поле с именем rating , в котором будет храниться средний рейтинг пользователя. В таблице Review хранится идентификатор транзакции, идентификатор автора (который отправил обзор), значение (от 0 до 5). Наконец, транзакция содержит ссылку как для продавца, так и для покупателя.
Теперь предположим, что вы хотите обновить средний рейтинг для пользователя после того, как счетчик отправил отзыв. Запрос на обновление вычислит среднюю оценку для пользователя и поместит результат в качестве значения свойства User.rating
.
Я использовал следующий фрагмент кода с Doctrine 2.5 и Symfony3 . Поскольку работа касается пользователей, я имею смысл создать новую общедоступную функцию с именем updateRating( User $user)
в репозитории AppBundle \ Entity \ UserRepository.php .
/**
* Update the average rating for a user
* @param User $user The user entity object target
*/
public function updateRating( User $user )
{
// Compute Subrequest. The reference table being Transaction, we get its repository first.
$transactionRepo = $this->_em->getRepository('AppBundle:Transaction');
$tqb = $postRepo->createQueryBuilder('t');
#1 Computing select
$select = $tqb->select('SUM(r.value)/count(r.value)')
// My Review table as no association declared inside annotation (because I do not need it elsewhere)
// So I need to specify the glue part in order join the two tables
->leftJoin('AppBundle:Review','r', Expr\Join::WITH, 'r.post = p.id AND r.author <> :author')
// In case you have an association declared inside the Transaction entity schema, simply replace the above leftJoin with something like
// ->leftJoin(t.reviews, 'r')
// Specify index first (Transaction has been declared as terminated)
->where( $tqb->expr()->eq('t.ended', ':ended') )
// The user can be seller or buyer
->andWhere( $tqb->expr()->orX(
$tqb->expr()->eq('t.seller', ':author'),
$tqb->expr()->eq('t.buyer', ':author')
));
#2 The actual update query, containing the above sub-request
$update = $this->createQueryBuilder('u')
// We want to update a row
->update()
// Setting the new value using the above sub-request
->set('u.rating', '('. $select->getQuery()->getDQL() .')')
// should apply to the user we want
->where('u.id = :author')
// Set parameters for both the main & sub queries
->setParameters([ 'ended' => 1, 'author' => $user->getId() ]);
// Get the update success status
return $update->getQuery()->getSingleScalarResult();
}
Теперь с контроллера
// … Update User's rating
$em->getRepository('AppBundle:User')->updateRating($member);
// …