2014-01-22 67 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

好吧,事實證明,我真正需要的是使用交易。在foreach循環中保存400個模型:25秒。在beginTransaction&commit中包裝foreach循環: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類的方法是可行的。

相關問題