2013-08-29 20 views
6

ho bisogno di inserire più oggetto ActiveRecord in Yii, se tutti loro inseriteBatch inserto in Yii

$transaction = Yii::app()->db->beginTransaction(); 
for ($i = 0;$i < 10;$i++){ 
    $model = new Mymodel(); 
    $model->x = $i; 
    if (!$model->save()){ 
     $transaction->rollback(); 
     break; 
    } 
} 
if ($transaction->active) 
    $transaction->commit(); 

Ora ho bisogno di inserire tutti loro in una query, come posso farlo durante usando record attivo ?

+1

Non è possibile con ActiveRecord. –

+0

@MichaelHartl: un modo alternativo senza scrivere una query a mano? –

+1

È possibile utilizzare [DAO] (http://www.yiiframework.com/doc/guide/1.1/en/database.dao) o [query builder] (http://www.yiiframework.com/doc/guide /1.1/en/database.query-builder#building-data-manipulation-queries). Tuttavia, non ti sconvolgeranno entrambi dalla scrittura manuale degli inserti. –

risposta

6

Anche se non del tutto simile a Yii, può essere creato come un'estensione/componente e viene trattato come un normale comando, quindi le transazioni continuano a essere applicate. Sarebbe del tutto possibile impostarlo per utilizzare parametri piuttosto che stringhe letterali nella query e potrebbe anche implementare il controllo dei valori nulli e di default.

class CDbMultiInsertCommand extends CDbCommand{ 

/** @var CActiveRecord $class */ 
private $class; 

/** @var string $insert_template */ 
private $insert_template = "insert into %s(%s) "; 

/** @var string $value_template */ 
private $value_template = "(%s)"; 

/** @var string $query */ 
public $query; 

/** @var CDbColumnSchema[] $columns */ 
private $columns; 

/** @var boolean $fresh */ 
private $fresh; 

/** @var CDbConnection $db */ 
private $db; 

/** @param CActiveRecord $class 
* @param CDbConnection $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){ 
    /** @var CDbColumnSchema $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); 
} 

/** @param boolean $validate 
* @param CActiveRecord $record 
*/ 
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(); 
} 
} 

Uso sarebbe:

$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(); 

Naturalmente potrebbe essere reso più elaborato ed esteso per consentire aggiornamenti, ecc

Spero che questo aiuti.

+0

Si verifica questo problema, Dichiarazione di CDbMultiInsertCommand :: execute() deve essere compatibile con CDbCommand :: execute ($ params = Array) –

7

Una nuova versione di questa classe

class CDbMultiInsertCommand extends CDbCommand{ 

    /** @var CActiveRecord $class */ 
    private $class; 

    /** @var string $insert_template */ 
    private $insert_template = "insert into %s(%s) "; 

    /** @var string $value_template */ 
    private $value_template = "(%s)"; 

    /** @var string $query */ 
    public $query; 

    /** @var CDbColumnSchema[] $columns */ 
    private $columns; 

    /** @var boolean $fresh */ 
    private $fresh; 

    /** @var CDbConnection $db */ 
    private $db; 

    /** @param CActiveRecord $class 
    * @param CDbConnection $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; 
     } 

     parent::__construct($this->getConnection()); 
    } 
    private function createTemplate(){ 
     $this->fresh = true; 
     $value_template = ""; 
     $columns_string = ""; 
     $this->columns = $this->class->getMetaData()->tableSchema->columns; 
     $counter = 0; 
     foreach($this->columns as $column){ 
      /** @var CDbColumnSchema $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); 
    } 

    /** @param boolean $validate 
    * @param CActiveRecord $record 
    */ 
    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] = $record->{$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(){ 
     if(!$this->query) 
      return; 

     $this->setText($this->insert_template." ".$this->query); 
     return parent::execute(); 
    } 
} 

Uso sarebbe:

$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();