Как лучше сформировать запрос на удаление в Doctrine?

Необходимо удалить все значения по условиям из связанной таблицы.

  • News - содержит новости
  • NewsBad - содержит временные отчёты о недоступности ссылок на эти новости


Таблицы построены не верно, по бизнес-логике одна новость может иметь только один отчёт, но таблица NewsBad позволяет создавать несколько отчётов для одной и той же новости.

SQL код выглядит так:

DELETE     news_bad
FROM       smi_ad_news_bad  AS news_bad
INNER JOIN smi_ad_campaigns_news AS news ON news_bad.news_id = news.id
WHERE      news.status != "active"
AND        news_bad.dt < (now() - interval 1 month);


Пробую создать запрос на удаление :

$this->em
          ->getRepository(NewsBad::class)
          ->createQueryBuilder('nb')
          ->delete(NewsBad::class, 'nb')
          ->join(News::class, 'n')
          ->andWhere('n.status != :status')
          ->andWhere('n.dt < :date')
          ->setParameters([
              'date'   => $date,
              'status' => "active",
          ])
          ->getQuery()
          ->getSql()


Но тут, ошибка в в связи.... После долгих поисков, оказывается, что доктрина не умеет делать join на запрос удаления и предлагают воспользоваться несколькими запросами

Попробовал тот же запрос написать через DQL:
$qb = $this->em->createQuery('
          DELETE     newsBad
          FROM       AppBundle\Entity\NewsBad newsBad
          INNER JOIN AppBundle\Entity\News news ON newsBad.news_id = news.id
          WHERE      news.status != "active"
          AND        news_bad.dt < (now() - interval 1 month);
      ');

      $qb->execute();


Ничего не изменилось, так сделать всё равно нельзя?

Получилось сделать только через вложенный запрос:
return $this->createQueryBuilder('nb')
          ->delete()
          ->where($qb->expr()->in('nb.news', $this->getEntityManager()
              ->createQueryBuilder()
              ->select('n.id')
              ->from(News::class, 'n')
              ->where($qb->expr()->neq('n.status', "'active'"))
              ->getDQL()))
          ->andWhere('nb.dt < :older')
          ->setParameter('older', new \DateTime('-1 month'))
          ->getQuery()
          ->execute();


Меня такой вид записи очень печалит, может можно записать это лучше чем последний и единственно рабочий вариант?
  • Вопрос задан
  • 1534 просмотра
Решения вопроса 1
voronkovich
@voronkovich
Доктрина не умеет делать соединение внутри DELETE т.к. это не поддерживается всеми производителями БД. Например, это не умеет SQLite: https://www.sqlite.org/lang_delete.html

На мой взгляд, лучшее, что вы можете сделать - переписать запрос на DQL для удобочитаемости. Вам точно нужны конструкции вида: $qb->expr()->neq?
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы