2014年5月17日 星期六

yii framework - 如何一次寫入多筆資料?

假設現在要購買一台, 車的紀錄有顏色最高時速 (饒了我~ 我比較懶~先舉這兩個就好),
並且我們有個購物車清單陣列來紀錄所有要買的車.

一般我們新增 (insert)單筆資料時用的方法是 save(), 例如:

$car=new Car;        
$car->color=$color
$car->maxSpeed=$speed; 
if($car->save ()){ 
   echo "新增成功";  
}else{  
   echo "新增失败";  
}
但是當我們要新增多筆的時候呢? 例如:


$car=new Car;

$count = count($cartList['CarList']) - 1;
for($i=0; $i<=$count; $i++)
{
  $car->color=$color[$i]
  $car->maxSpeed=$speed[$i]
  if($car->save ()){ 
     echo "新增成功";  
  }else{  
     echo "新增失败";  
  }
}

這時候檢查資料庫的時候會發現只有新增到購物車清單最後一筆資料!怎麼會這樣呢?

讓我們來抽絲剝繭吧!首先我們先看一下save()方法吧~

public function save($runValidation=true,$attributes=null)
{
    if(!
$runValidation || $this->validate($attributes))
        return 
$this->getIsNewRecord() ? $this->insert($attributes) : $this->update($attributes);
    else
        return 
false;
}

哦~原來他會確認這筆資料是不是新的, 如果是, 就新增一筆資料. 如果不是, 就更新這筆資料!

也就是說, 如果我們要買三台車, 第一台車會新增進去, 第二跟第三則會用更新的方式處理....

這下尷尬了..那怎麼辦呢? 不要怕, 我們接著看一下
getIsNewRecord()跟 insert()方法



先看一下insert()的code:

public function insert($attributes=null)
{
    if(!
$this->getIsNewRecord())
        throw new 
CDbException(Yii::t('yii','The active record cannot be inserted to database because it is not new.'));
    if(
$this->beforeSave())
    {
        
Yii::trace(get_class($this).'.insert()','system.db.ar.CActiveRecord');
        
$builder=$this->getCommandBuilder();
        
$table=$this->getMetaData()->tableSchema;
        
$command=$builder->createInsertCommand($table,$this->getAttributes($attributes));
        if(
$command->execute())
        {
            
$primaryKey=$table->primaryKey;
            if(
$table->sequenceName!==null)
            {
                if(
is_string($primaryKey) && $this->$primaryKey===null)
                    
$this->$primaryKey=$builder->getLastInsertID($table);
                else if(
is_array($primaryKey))
                {
                    foreach(
$primaryKey as $pk)
                    {
                        if(
$this->$pk===null)
                        {
                            
$this->$pk=$builder->getLastInsertID($table);
                            break;
                        }
                    }
                }
            }
            
$this->_pk=$this->getPrimaryKey();
            
$this->afterSave();
            
$this->setIsNewRecord(false);
            
$this->setScenario('update');
            return 
true;
        }
    }
    return 
false;
}

前面密密麻麻的很複雜? 沒關係, 我們先跳過. 重點是可以看到當新增完後, 他會將setIsNewRecord設成 false, 並且將setScenario的參數帶入update!怪不得當第一筆新增完後,
 $this->getIsNewRecord() 的結果會是 false, 這下找到原因了!



再接著看看getIsNewRecord():

public function getIsNewRecord()
{
    return 
$this->_new;
}


官方的說明是:

該記錄是否是新的,就插入時調用save。在構造函數和populateRecord自動設置此屬性。默認值為false, 如果使用new運算符創建實例,它會被設置為true。

看到重點了吧!原來要使用new阿~
所以我們重新調整一下原來的code吧!


$count = count($cartList['CarList']) - 1;
for($i=0; $i<=$count; $i++)
{
  $car=new Car; <- 這行改到迴圈內就可以了!
  $car->color=$color[$i]
  $car->maxSpeed=$speed[$i]
  if($car->save ()){ 
     echo "新增成功";  
  }else{  
     echo "新增失败";  
  }
}

雖然最後結果很簡單!不過還是仔細的看了官方的code才找到真正的原因阿^^

大家一起繼續加油吧!晚安

沒有留言:

張貼留言