Although this is not exactly Yii, it can be executed as an extension / component and is treated as a normal command, so transactions are still applied. It would be entirely possible to set this to use parameters, rather than string literals in the query, and also implement checking for null values ββand default values.
class CDbMultiInsertCommand extends CDbCommand{ private $class; private $insert_template = "insert into %s(%s) "; private $value_template = "(%s)"; public $query; private $columns; private $fresh; private $db; public function __construct($class, $db = null){ $this->class = $class; $this->createTemplate(); if(is_null($db)){ $this->db = Yii::app()->db; } else{ $this->db = $db; } } private function createTemplate(){ $this->fresh = true; $value_template = ""; $columns_string = ""; $this->columns = $this->class->getMetaData()->tableSchema->columns; $counter = 0; foreach($this->columns as $column){ if($column->autoIncrement){ $value_template .= "0"; } else if($column->type == "integer" || $column->type == "boolean" || $column->type == "float" || $column->type == "double") { $value_template .= "%d"; } else{ $value_template .= "\"%s\""; } $columns_string .= $column->name; $counter ++; if($counter != sizeof($this->columns)){ $columns_string .= ", "; $value_template .= ", "; } } $this->insert_template = sprintf($this->insert_template, $this->class->tableName(), $columns_string); $this->value_template = sprintf($this->value_template, $value_template); } public function add($record, $validate = true){ $values = array(); if($validate){ if(!$record->validate()){ return false; } } $counter = 0; foreach($this->columns as $column){ if($column->autoIncrement){ continue; } $values[$counter] = $this->class->{$column->name}; $counter ++; } if(!$this->fresh){ $this->query .= ","; } else{ $this->query = "values"; } $this->fresh = false; $this->query .= vsprintf($this->value_template, $values); return true; } public function getConnection(){ return $this->db; } public function execute(){ $this->setText($this->insert_template." ".$this->query); return parent::execute(); } }
Using:
$transaction = Yii::app()->db->beginTransaction(); $multi = new CDbMultiInsertCommand(new Mymodel()); for ($i = 0;$i < 10;$i++){ $model = new Mymodel(); $model->x = $i; $multi->add($model, $shouldBeValidated); } $multi->execute(); if ($transaction->active) $transaction->commit();
Of course, it could be made more complex and expanded for updating, etc.
Hope this helps.
source share