Массовая вставка Cakephp 3.0

В Cakephp 3.0 для сохранить много записей указано использовать функцию saveMany.

https://book.cakephp.org/3.0/en/orm/saving-data.html#saving-multiple-entities

Однако приведенный выше оператор вставки отправки по одному.

Мне нужно обновить несколько тысяч записей одновременно, поэтому я хотел бы использовать пакетная вставка моих записей, а не вставлять их по одной.

Чтобы проверить это, я попробовал saveMany поведение. Я проверил свое querys.log, похоже, что использование saveMany не вставляет мой запрос в пакет, а действительно вставляет его один за другим.

Другими словами, я хотел бы иметь это:

INSERT INTO mytable (id, code) VALUES ('123', 'code_a'), ('123', 'code_b'), ('123', 'code_c'), ('123', 'code_d'), ('123', 'code_e');

Но вместо этого было выполнено следующее

INSERT INTO mytable (id, code) VALUES ('123', 'code_a')
INSERT INTO mytable (id, code) VALUES ('123', 'code_b')
INSERT INTO mytable (id, code) VALUES ('123', 'code_c')
INSERT INTO mytable (id, code) VALUES ('123', 'code_d')
INSERT INTO mytable (id, code) VALUES ('123', 'code_e')

Итак, мой вопрос, как я могу сделать объемная вставка в Тортphp 3.0

Примечание. Я провел небольшое исследование и обнаружил, что функция saveAll была в Тортphp 2.0 и могла выполнять пакетную обработку (предположительно), но, к сожалению, такой функции нет в версии 3.0.

🤔 А знаете ли вы, что...
Фреймворк обладает встроенной системой логирования и отладки приложений.


1
1 208
4

Ответы:

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

<?php
    $sql = "INSERT INTO mytable ";
    $binding = [];
    $insertSql = [];
    foreach($myEntitys as $i => $myEntity){
        $myEntityArray = $myEntity->toArray();
        $myEntityArrayKeys = array_keys($myEntityArray);

        if ($i === 0){
            $sql .= "(";
            $sql .= implode(",", $myEntityArrayKeys);
            $sql .= ")";
        }

        $singleInsertSql = [];
        foreach($myEntityArrayKeys as $key) {
            $value = $myEntityArray[$key];
             $singleInsertSql[] = "?";
             $binding[] = $value;
        }
        $insertSql[] = "(" . implode(",", $singleInsertSql) . ")";
    }
    $sql .= " VALUES " . implode(",", $insertSql);

    $connection = ConnectionManager::get('default');
    $connection->execute($sql, $binding);

Это делает работу, но очень уродливо, надеюсь, кто-то может опубликовать более собственный метод торта, спасибо!


$mytable = TableRegistry::getTableLocator()->get('ModelNameOfTable');

foreach ($myEntitys as $row)
{
    $record = $mytable->newEntity();

    foreach ($row as $column => $value)
    {
        $record->{$column} = $value;
    }

    if ($mytable->save($record))
    {
        $id = $record->id; // for checking if needed
    }
}

Что-то вроде этого должно сделать это.

Просто ссылка: https://book.cakephp.org/3.0/en/orm/saving-data.html

ХОТЯ, если ваша таблица довольно сложна и вам потребуется много перекрестных ссылок/проверок полей, создание собственного пользовательского выполнения SQL, как вы, может быть более подходящим.

Идеал использования ORM и моделей состоит в том, чтобы обеспечить возможность совместного использования кода на разных платформах (моделях) баз данных. В вашем случае вы пишете что-то для «передачи» данных, а не для обмена.


  • Когда вы делаете «массовую» вставку с помощью INSERT INTO mytable (id, code) VALUES ('123', 'code_a'), ('123', 'code_b'), ('123', 'code_c'), ('123', 'code_d'), ('123', 'code_e');, вы отправляете все данные вставки в одном запросе sql без проверки, но сама база данных в фоновом режиме вставляется одна за другой.
  • В ORM ваше приложение сначала выполняет проверку данных, а затем создает sql-запрос для текущего объекта. Не большая разница в скорости.

Решено

Массовые вставки в cakephp довольно просты:

<?php 

$query = $this->MyModel->query(); 

foreach ($data as $row) {
    $query
        ->insert(['column1', 'column2'])
        ->values([
            'column1' => $row['value1'], 
            'column2' => $row['value2']
        ]);
}

$query->execute();