Activerecord 批量插入Yii
我需要在Yii中插入多个ActiveRecord对象(如果所有对象都已插入)Activerecord 批量插入Yii,activerecord,yii,insert,yii1.x,Activerecord,Yii,Insert,Yii1.x,我需要在Yii中插入多个ActiveRecord对象(如果所有对象都已插入) $transaction = Yii::app()->db->beginTransaction(); for ($i = 0;$i < 10;$i++){ $model = new Mymodel(); $model->x = $i; if (!$model->save()){ $transaction->rollback();
$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();
$transaction=Yii::app()->db->beginTransaction();
对于($i=0;$i<10;$i++){
$model=新的Mymodel();
$model->x=$i;
如果(!$model->save()){
$transaction->rollback();
打破
}
}
如果($transaction->active)
$transaction->commit();
现在,我需要在一个查询中插入所有数据,在使用活动记录期间如何执行此操作?虽然不完全是我喜欢的,但它可以作为扩展/组件,并被视为普通命令,因此事务仍然适用。完全可以将此设置为在查询中使用参数而不是字符串文本,还可以实现空值和默认值的检查
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();
}
}
用途如下:
$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();
$transaction=Yii::app()->db->beginTransaction();
$multi=新的CDbMultiInsertCommand(新的Mymodel());
对于($i=0;$i<10;$i++){
$model=新的Mymodel();
$model->x=$i;
$multi->add($model,$shouldbeevalidate);
}
$multi->execute();
如果($transaction->active)
$transaction->commit();
当然,它可以更加详细和扩展,以允许更新等
希望这有帮助。这门课的新版本
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();
}
}
用途如下:
$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();
$transaction=Yii::app()->db->beginTransaction();
$multi=新的CDbMultiInsertCommand(新的Mymodel());
对于($i=0;$i<10;$i++){
$model=新的Mymodel();
$model->x=$i;
$multi->add($model,$shouldbeevalidate);
}
$multi->execute();
如果($transaction->active)
$transaction->commit();
批量插入/批量插入YII的更新
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 $keyColumnName => $column){
/** @var CDbColumnSchema $column */
if($column->autoIncrement){
unset($this->columns[$keyColumnName]);
continue;
// $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);
$this->query = str_replace('"', "'", $this->query);
return true;
}
public function getConnection(){
return $this->db;
}
public function execute($params=array()){
if(!$this->query)
return;
$this->setText($this->insert_template." ".$this->query);
return parent::execute();
}
}
我在前面的代码中遇到了3个问题
Yii::app()->db->getCommandBuilder()
->createMultipleInsertCommand('table_name', $data)
->execute();
对于模型数组,您可能可以通过这种方式生成$data
(注意,它不会进行任何验证):
您不能使用ActiveRecord。@MichaelHartl:没有手工编写查询的其他方法吗?您可以使用或。但是,它们都不会解除您手动编写插入的负担。为什么需要将它们全部作为单个查询插入?当然,使用事务的方式与您的方式几乎完全相同,您可以将其作为单独的查询插入,但仍然可以在必要时回滚,@ZackNewsham:bulk insert有一些好处,执行查询比执行查询更快,它使用的php和数据库之间的网络更少,等等。我明白了这个问题,CDbMultiInsertCommand::execute()的声明应该与CDbCommand::execute($params=Array)@MohdShahid兼容,只需在扩展的
execute
函数的参数中添加$param。看起来是SQL注入的好方法(与此问题中的其他答案相同)。。。
$data = [];
foreach ($models as $model) {
$data[] = $model->getAttributes();
}