dragonmeng2002 2013-04-25 16:42
浏览 69
已采纳

CakePHP:创建新的HABTM行而不是更新其他行

I have two models with a HABTM (Has and belongs to many) relationship: Qsets and Questions.

The following action (in QsetsController.php) should result in a new row in the qsets_questions table, with the new question appearing in the new qset. But instead it updates existing rows, resulting in that question begin taken from a previous qset and added to the new one.

What am I doing wrong?

public function admin_add_question( $qset_id, $question_id) {

    //find the qset...
    $qset = $this->Qset->find('first', array('id'=>$qset_id));

    $this->Qset->QsetsQuestion->create();
    $data = array(
            "Qset"=> array ("id"=>$qset_id),
            "Question"=>array ("id"=>$question_id)
    );
    Controller::loadModel('Question');
    $r= $this->Question->save($data);

    $this->Session->setFlash('Question id['.$question_id.'] added.');

    $this->redirect( $this->referer() );
}

In case it wasn't clear from my description, here happens:

Before adding a question...

**Qset 1**
Question 1
Question 2

**Qset 2**
Question 3
Question 4

What should happen when adding Question 2 to Qset 2

**Qset 1**
Question 1
Question 2

**Qset 2**
Question 3
Question 4
Question 2

What happens instead...

**Qset 1**
Question 1
          <----removed
**Qset 2**
Question 3
Question 4
Question 2

update: Here's a dump of my qsets_questions table:

CREATE TABLE `qsets_questions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `question_id` int(11) NOT NULL,
  `qset_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=64 ;

Solution:

Here's the working version, thanks to @nuns

public function admin_add_question( $qset_id, $question_id) {

    $this->Qset->QsetsQuestion->create();
    $data = array(
            "qset_id"=>$qset_id,
            "question_id"=>$question_id
    );
    Controller::loadModel('Question');
    $this->Question->QsetsQuestion->save($data);
    $this->Session->setFlash('Question id['.$question_id.'] added.');       
    $this->redirect( $this->referer() );
}
  • 写回答

1条回答 默认 最新

  • dongzuozhu66776 2013-04-25 18:15
    关注

    Ok, here is what I think is happening:

    Your not using the super useful HABTM relation magic. Instead of treating this table as a mere relation table, cake goes to the defined model an sees the relations you have defined and primaryKeys and displayFields, etc.

    That's ok when you have a complicated HABTM table. But if that's the case, your data array is all messed up, because your not adding a Question and Qset separately. What I mean is, your not doing

    $data = array('Question'=>array('title'=>'new_question'),
                  'Qset'=>array('name'=>'lets say qset'));
    $this->Question->saveAll($data);
    

    Doing that, you let cake resolve the HABTM association for you, and that data structure would be ok. But you have your own QsetsQuestion model in you model folder. So the data you save should be like with any other table, like so

    $data = array('qset_id'=> $qset_id,
                  'question_id'=> $question_id);
    $this->Question->QsetsQuestion->save($data);
    

    And that creates a new id in qsets_questions table, with the new relation, just like you want.

    Be careful, though, since your using your own model for this, if you don't set you validations correctly, you might have the same pair of foreign keys a lot of times, because by default cake just check that the id must be unique.

    [EDIT] After a bit of clarification, the solution above does solve the "problem", but isn't actually the reason for this behavior.

    Cakephp has a feature

    By default when saving a HasAndBelongsToMany relationship, Cake will delete all rows on the join table before saving new ones. For example if you have a Club that has 10 Children associated. You then update the Club with 2 children. The Club will only have 2 Children, not 12.

    So when you want to add a new row, cake deletes all previous associations and add the new ones. A way to solve this is to find all the Qsets that belong to a question and add them to the $data array (with the addition of the new question association you want to add). This link helped me to understand HABTM associations (look for "Challenge IV").

    I know the solution I gave before helped you with the "problem", but it was made under the impression you had a QsetsQuestion model file somewhere. Since you don't, the solution would be to get all Questions associated and add them as a new array. Or actually create a QsetsQuestion model, and make the associations like this:

    Qset hasMany QsetsQuestion
    QsetsQuestion belongsTo Qset, Question
    Question hasMany Qsets.
    

    Or change the behavior of cake... None of them seems pretty, I know.

    So, summary for solutions:

    • Every time you want to save a new Qset-Question association, retrieve the previously stored associations, put it in the array to be saved, and save them

      //find previously associated Qsets, lets say it's 1,2,3 and 4
      $data = array('Question'=>array('id'=>1),
                'Qsets'=>array('Qsets'=>array(1,2,3,4, $new_qset));
      $this->Question-save($data);
      

    Note there's no QsetsQuestion, since it doesn't exists. This should be the first option since the HABTM model is not complex

    OR

    • Create QsetsQuestion in your model folder and change the associations as indicated above. The save part on the controller would be

      $data = array('qset_id'=>1, 'question_id'=>1)
      $this->Question->QsetsQuestion->save($data);    //also works with $this->Qset->QsetsQuestion
      

    It is much more simple (maybe), but you have to create a new file, and remember to check that there's no previous similar association (check if 2-2 tuple exists before inserting it). Simple validation rules should work.

    OR

    • Change cakephp behavior for this... I don't like this one.
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 flink cdc无法实时同步mysql数据
  • ¥100 有人会搭建GPT-J-6B框架吗?有偿
  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名