OTCloud
@OTCloud
- И как назовемся? Пожиратели пожирателей смерти?

Как сделать нативный SQL запрос для UPDATE с WHERE IN условием Doctrine 2?

Задача: сделать запрос следущего вида
UPDATE some_table SET some_field = ? WHERE IN (?, ?, ?, ..., ?)
;
Кейс: удаление Воронки №1 из CRM и массовое перемещение лидов из Воронки №1 в Воронку №2;
  • Вопрос задан
  • 127 просмотров
Решения вопроса 2
OTCloud
@OTCloud Автор вопроса
- И как назовемся? Пожиратели пожирателей смерти?
Решение под Symfony 4 и Doctrine 2
Делаем свой абстрактный слой для базы данных
https://www.doctrine-project.org/projects/doctrine...

Настраиваем конфигурацию для DBAL
# the DBAL wrapperClass option
wrapper_class: App\DBAL\MyConnectionWrapper

https://symfony.com/doc/current/reference/configur...

В кастомном DBAL делаем следущую реализацию, также незабываем перенести все private свойства и методы из донора Doctrine\DBAL\Connection:
public function update($table, array $data, array $criteria, array $types = [])
    {
        $columns = $values = $conditions = $set = [];

        foreach ($data as $columnName => $value) {
            $columns[] = $columnName;
            $values[]  = $value;
            $set[]     = $columnName . ' = ?';
        }

        $this->addCriteriaCondition($criteria, $columns, $values, $conditions);

        if (is_string(key($types))) {
            $types = $this->extractTypeValues($columns, $types);
        }

        $sql = 'UPDATE ' . $table . ' SET ' . implode(', ', $set)
                . ' WHERE ' . implode(' AND ', $conditions);

        return $this->executeStatement($sql, $values, $types);
    }

    private function addCriteriaCondition(
        array $criteria,
        array &$columns,
        array &$values,
        array &$conditions
    ): void {
        $platform = $this->getDatabasePlatform();

        foreach ($criteria as $columnName => $value) {
            if ($value === null) {
                $conditions[] = $platform->getIsNullExpression($columnName);
                continue;
            }

            if(is_array($value)) {
                $this->addInCriteriaCondition($columns, $values, $conditions, $value, $columnName);
                continue;
            }

            $columns[]    = $columnName;
            $values[]     = $value;
            $conditions[] = $columnName . ' = ?';
        }
    }

    private function addInCriteriaCondition(
        array &$columns,
        array &$values,
        array &$conditions,
        array $valuesArray,
        $columnName
    ) {
        $condition = $columnName . ' IN (';

        foreach($valuesArray as $index => $value) {
            $columns[]    = $columnName;
            $values[]     = $value;
            $condition    .= '?';

            if($index != count($valuesArray) - 1) {
                $condition    .= ', ';
            }
        }
        
        $conditions[] = $condition . ')';
    }
Ответ написан
BoShurik
@BoShurik Куратор тега Symfony
Symfony developer
Doctrine это умеет из коробки

Можно через DBAL с помощью обычного SQL (это именно то, что спрашивается в вопросе)
$ids = [1, 2, 3, 4];

$this->getEntityManager()->getConnection()
    ->executeStatement('UPDATE some_table SET some_field = ? WHERE id IN (?)', [
        'value',
        $ids,
    ], [
        1 => Connection::PARAM_INT_ARRAY,
]);


Можно через QueryBuilder
$builder = $this->getEntityManager()->getConnection()->createQueryBuilder();
$builder
    ->update('some_table')
    ->set('some_field', ':value')
    ->where($builder->expr()->in('id', ':ids'))
    ->setParameter('value', 'value')
    ->setParameter('ids', $ids, Connection::PARAM_INT_ARRAY)
;

$builder->execute()


Если все-таки используется DQL и ORM, то можно и через нее:
$this->getEntityManager()
    ->createQuery('UPDATE App\Entity\SomeEntity se SET se.someValue = :value WHERE se.id IN (:ids)')
    ->execute(new ArrayCollection([
        new Parameter('value', 'value'),
        new Parameter('ids', $ids),
    ]))
);


Либо через QueryBuilder
$builder = $this->createQueryBuilder('se');
$builder
    ->update()
    ->set('se.someValue', ':value')
    ->where($builder->expr()->in('uu.id', ':ids'))
    ->setParameter('value', 'value')
    ->setParameter('ids', $ids)
;

$builder->getQuery()->execute();
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы