2014-01-22 6 views
1

Я пытаюсь сохранить много объектов модели CActiveRecord в цикле. у меня есть что-то вроде этого:Yii: сохранение нескольких записей в одном запросе

foreach ($array_of_items as $item) { 

    $values = array(
     "title" => $item->title, 
     "content" => $item->content, 
    ); 

    $object = new MyModel; 
    $object->attributes = $values; 
    $object->save(); 

} 

В моем случае, это создает около 400 объектов, метод CActiveRecord. Процесс сохранения очень медленный, потому что каждый save() запрашивает базу данных.

Есть ли способ сохранить все эти объекты за один раз? Что-то вроде:

$objects = array(); 

foreach ($array_of_items as $item) { 

    $values = array(
     "title" => $item->title, 
     "content" => $item->content, 
    ); 

    $object = new MyModel; 
    $object->attributes = $values; 
    $objects[] = $object; 
} 

save_all_objects($objects); 

Я не мог найти что-нибудь по этому вопросу. Кто угодно?

+0

Нет ничего, что можно было бы сделать в Yii из количества времени, которое я потратил на это, то, как вы делаете это сейчас, должно быть единственным вариантом, по всей вероятности, - заинтересовался, чтобы узнать, есть ли альтернативы. – Rohan

+1

Я думаю, что вы можете найти свое решение в принятом ответе [этого вопроса] (http://stackoverflow.com/questions/18518001/batch-insert-in-yii). – ndgraef

+0

Хорошо, получается, что мне действительно нужно было использовать транзакцию. Сохранение 400 моделей в петле foreach: 25 секунд. Завершение цикла foreach в beginTransaction & commit: 0,36 секунды. –

ответ

4

вы можете validate() модель, и если это было нормально вы можете добавить его так SQL текст для вставки

и после цикла, просто использовать базы данных и выполнить Ваш готовый текст

$sql = ''; 
if($object->validate()) 
{ 
    $sql .= ',("' . $object->attr1 . '")'// append to script,(you get the idea, you need to also make a correct values) 
} 

... 

if(!empty($sql)) 
{ 
    $sql = 'INSERT INTO table (attr1) Values' . $sql;// make complete script 
    // execute that command 
} 
0

Для вставки нескольких строк, введите этот код в папку components под именем GeneralRepository.php.

<?php 
class GeneralRepository 
{ 
    /** 
    * Creates and executes an INSERT SQL statement for several rows. 
    * 
    * Usage: 
    * $rows = array(
    *  array('id' => 1, 'name' => 'John'), 
    *  array('id' => 2, 'name' => 'Mark') 
    *); 
    * GeneralRepository::insertSeveral(User::model()->tableName(), $rows); 
    * 
    * @param string $table the table that new rows will be inserted into. 
    * @param array $array_columns the array of column datas array(array(name=>value,...),...) to be inserted into the table. 
    * @return integer number of rows affected by the execution. 
    */ 
    public static function insertSeveral($table, $array_columns) 
    { 
     $connection = Yii::app()->db; 
     $sql = ''; 
     $params = array(); 
     $i = 0; 
     foreach ($array_columns as $columns) { 
      $names = array(); 
      $placeholders = array(); 
      foreach ($columns as $name => $value) { 
       if (!$i) { 
        $names[] = $connection->quoteColumnName($name); 
       } 
       if ($value instanceof CDbExpression) { 
        $placeholders[] = $value->expression; 
        foreach ($value->params as $n => $v) 
         $params[$n] = $v; 
       } else { 
        $placeholders[] = ':' . $name . $i; 
        $params[':' . $name . $i] = $value; 
       } 
      } 
      if (!$i) { 
       $sql = 'INSERT INTO ' . $connection->quoteTableName($table) 
       . ' (' . implode(', ', $names) . ') VALUES (' 
       . implode(', ', $placeholders) . ')'; 
      } else { 
       $sql .= ',(' . implode(', ', $placeholders) . ')'; 
      } 
      $i++; 
     } 
     $command = Yii::app()->db->createCommand($sql); 
     return $command->execute($params); 
    } 
} 

А использование в любом месте:

$rows = array(
    array('id' => 1, 'name' => 'John'), 
    array('id' => 2, 'name' => 'Mark') 
); 
GeneralRepository::insertSeveral(User::model()->tableName(), $rows); 
0

С v1.1.14, метод createMultipleInsertCommand() из CDbCommandBuilder класса доступен.

Смежные вопросы