2013-03-04 90 views
6

我有一个与复合键(user_id,category_id)的MySQL表; 我试图更新这些记录的最后一次访问如下Yii复合主键与isNewRecord

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

$userCategory->save(); 

的{$ userCategory-> isNewRecord},当我尝试保存()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; 
} 
+0

检查我的答案中的编辑是否适用于填充新记录。 – Snivs 2013-03-13 16:00:17

回答

1

如果你想更新,你应该载入记录,而不是创建一个新的。

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

我不知道我是否正在更新或插入。我需要插入,如果它是一个新的记录,否则更新,类似于“重复更新” – gadelkareem 2013-03-05 10:36:56

+0

控制器内有两种不同的功能,处理actionUpdate中的更新并插入actionCreate – ShaunUK 2013-03-07 13:30:48

+0

我不是在谈论控制器!这是一个不同的过程 – gadelkareem 2013-03-07 14:34:44

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; 
} 

以上是由我用了很多做一个更常用的方法激发了创造,或者找到的-IF-already-存在过程。

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

$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'; 
} 
7

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

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

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

因此,要解决这一点,你必须找到记录并评估如果在保存之前发现的,而不是。文档还可以阅读Here有关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
在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(); 
---- 
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); 
} 

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

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

应根据关闭它是否找到了记录插入或更新,所以你不必更改任何其他代码。

+0

仅供参考我试图在beforeSave()第一次执行此操作。但是,当save()函数由于某种原因而运行时,isNewRecord被重置为true。 – Pitchinnate 2013-03-08 15:44:09