使用isNewRecord的Yii复合主键

时间:2013-03-04 12:37:07

标签: php mysql yii

我有一个带有复合键的mysql表(user_id,category_id); 我正在尝试更新这些记录的最后一次访问,如下所示

$userCategory = new UserCategory;
$userCategory->user_id = 1;
$userCategory->category_id = 15;
echo $userCategory->isNewRecord; //always true
$userCategory->last_access = Now();

$userCategory->save();

{$ userCategory-> isNewRecord},当我尝试save()时,MySQL会为复合主键生成重复错误。

我还将此添加到UserCategory模型但没有帮助

public function primaryKey() {
        return array('user_id', 'category_id');
    }

****更新: 对困惑感到抱歉。我的问题是如何在Yii框架中实现与“ON DUPLICATE KEY UPDATE”相同的结果。换句话说,如何在一个SQL查询中插入或更新。如果你看一下save()

的源代码
public function save($runValidation=true,$attributes=null)
{
    if(!$runValidation || $this->validate($attributes))
        //checking if new record
        return $this->getIsNewRecord() ? $this->insert($attributes) : $this->update($attributes);**
    else
        return false;
}

5 个答案:

答案 0 :(得分:7)

实际上,问题是如果isNewRecord始终为true,则意味着在将模型保存到数据库时,Yii将使用INSERT语句而不是UPDATE语句..这就是为什么你总是得到重复的pk错误,即使它是复合的。

Here是关于IsNewRecord的官方文档。所以,问题是你正在使用

$userCategory = new UserCategory; //Always a new record, tries to INSERT

因此,要解决此问题,您必须找到记录并在保存之前评估是否找到记录。有关find()方法系列及其返回值的文档也可以阅读Here,find()方法的返回值因其性质而略有不同:

  

find ..()返回找到的记录,如果没有找到记录则返回NULL

     

findAll ..()返回一个包含找到的所有记录的数组,如果没有找到记录,则返回一个空数组。

您可以使用此返回值来区分主键是否存在:

$userCategory = UserCategory::model()->findByAttributes(array('user_id '=>1,'category_id '=>15));
// if user does not exist, you need to create it
if ($userCategory == NULL) {
     $userCategory = new UserCategory;
     $userCategory->user_id = 1;
     $userCategory->category_id = 15;
}
echo $userCategory->isNewRecord; //you will see the difference if it does exist or not exist
$userCategory->last_access = Now();
$userCategory->save();

这将确保框架正确使用INSERT或UPDATE语句,避免您遇到重复的PK错误。

修改:增强了示例代码,以便在新记录时正确填充记录。

答案 1 :(得分:3)

在您的模型中,添加以下方法:

/**
* Uses the primary keys set on a new record to either create or update
* a record with those keys to have the last_access value set to the same value
* as the current unsaved model.
*
* Returns the model with the updated last_access. Success can be checked by
* examining the isNewRecord property.
*
* IMPORTANT: This method does not modify the existing model.
**/

public function updateRecord(){
  $model = self::model()->findByPk(array('user_id'=>$this->user_id,'category_id'=>$this->category_id));

  //model is new, so create a copy with the keys set
  if(null === $model){
    //we don't use clone $this as it can leave off behaviors and events
    $model = new self;
    $model->user_id = $this->user_id;
    $model->category_id = $this->category_id;
  }

  //At this point we have a model ready for saving, 
  //and don't care if it is new or not
  $model->last_access = $this->last_access;
  $model->save(false);
  return $model;
}

以上内容的灵感来自于一种更为通用的方法,我使用它来创建或查找已存在的过程。

使用以下代码执行此操作。

$userCategory = new UserCategory;
$userCategory->user_id = 1;
$userCategory->category_id = 15;
echo $userCategory->isNewRecord; //always true
$userCategory->last_access = Now();

$userCategory = $userCategory->updateRecord();

请注意,只有最后一行与您的代码不同。使用new UserCategory声明的模型实例未被更改的事实是预期的行为。

然后,您可以在代码中验证模型是否使用以下内容保存:

if(!$userCategory->isNewRecord){
  echo 'save succeeded';
}
else{
  echo 'save failed';
}

答案 2 :(得分:1)

如果您正在尝试更新,则应加载记录,而不是创建新记录。

UserCategory::model()->findByPk(array('user_id'=> 1,'category_id '=> 15));
$userCategory->last_access = Now();
$userCategory->save();

答案 3 :(得分:1)

UserCategory.php中的

public function isNewRecord()
{
    $result = $this->findByAttributes(array('user_id'=>$this->user_id,'category_id'=>$this->category_id));
    if($result === NULL)
    {
        return true;
    }
    return false;
}

然后在控制器中

$userCategory = new UserCategory;
$userCategory->user_id = 1;
$userCategory->category_id = 15;
echo $userCategory->isNewRecord(); 
----

答案 4 :(得分:0)

另一种选择是修改模型以更改保存功能的条件,然后调用父保存功能:(此代码进入UserCategory模型)

public function save($runValidation=true,$attributes=null) {
    $exists = UserCategory::model()->findByAttributes(array('category_id'=>$this->category_id,'user_id'=>$this->user_id));
    if($exists) {
        $this->isNewRecord = false;
    }
    return parent::save($runValidation,$attributes);
}

我刚做了一个测试,似乎工作正常。你应该能够做到这一点:

$userCategory = new UserCategory;
$userCategory->user_id = 1;
$userCategory->category_id = 15;
$userCategory->last_access = Now();
$userCategory->save();

应根据是否找到记录来插入或更新,因此您不必更改任何其他代码。