在CakePHP中使HABTM关系独特

时间:2010-03-07 11:24:17

标签: php cakephp model has-and-belongs-to-many

我有两个名为Book和Tag的模型,它们处于HABTM关系中。我想要一对(书,标签)只保存一次。在我的模特中我有

var $hasAndBelongsToMany = array(
    'Tag' => array(
        'className' => 'Tag',
        'joinTable' => 'books_tags',
        'foreignKey' => 'book_id',
        'associationForeignKey' => 'tag_id',
        'unique' => true
    )
);

反之,但独特的旗帜对我没有帮助;我仍然可以挽救同一对夫妇两次。

我如何在CakePHP中执行此操作?我应该直接在数据库中声明这对(book,tag)是唯一的,还是会让CakePHP变得疯狂?是否有一种Cakey方法来处理这种情况?

编辑:我试图让这对夫妇与查询一致(我正在使用MySQL)

ALTER TABLE books_tags ADD UNIQUE (book_id,tag_id);

但是效果不好。当我一次保存多个标签时,如果所有夫妻都是新人,一切都顺利。如果至少有一对夫妇被重复,那么CakePHP无法完成整个操作,因此它不会保存任何新的夫妻(甚至不是好夫妻)。

4 个答案:

答案 0 :(得分:3)

Cake通常保存HABTM数据的方式是从HABTM表中删除模型的所有现有数据,并从您提供的数据数组中重新插入所有关系save()。如果您只是以这种方式处理HABTM关系,那么您应该没有问题。

当然,这并不总是理想的方式。要在HABTM表上强制执行验证,您需要为其创建模型并添加一些自定义验证,如下所示:

class BooksTag extends AppModel {

    var $validate = array(
        'book_id' => array('rule' => 'uniqueCombi'),
        'tag_id'  => array('rule' => 'uniqueCombi')
    );

    function uniqueCombi() {
        $combi = array(
            "{$this->alias}.book_id" => $this->data[$this->alias]['book_id'],
            "{$this->alias}.tag_id"  => $this->data[$this->alias]['tag_id']
        );
        return $this->isUnique($combi, false);
    }

}

只需确保使用saveAll($data, array('validate' => 'first'))保存数据即可触发验证。

可能必须在关系中明确指定BooksTag模型:

var $hasAndBelongsToMany = array(
    'Tag' => array(
        ...
        'with' => 'BooksTag'
    )
);

如果最重要的是,你还要在数据库级别上强制执行唯一性,那就更好了。

答案 1 :(得分:1)

在我看来,任何时间你有数据要求,这些要求应该在数据(基础)级别指定。在尽可能低的水平上执行您的规则。如果应用程序也可以执行这些规则,并且您选择这样做,那么我会说它不会受到伤害。不过,我建议不要使用应用程序作为执行数据约束的唯一方法。

答案 2 :(得分:1)

我建议您将约束放在数据库模式中。如果你可以将组合列声明为主键,那将很容易,尽管我认为这会导致蛋糕出现问题。

根据您使用的RDBMS,您可以创建组合行索引并在其上声明唯一约束。

你在Cake中保留这个逻辑的另一个选择是改变Book模型中的beforeSave()函数,这样它首先在传递的数据上运行一个find(),并且只有在find返回时才会保存false(意思是没有先前的对,意味着你已经完成了你的唯一约束)。

我不承诺的一个选项可行,但看起来可能是CakePHP Counter Cache行为。不确定它是否默认使用HABTM,但是这里是蛋糕簿的链接(http://book.cakephp.org/view/816/counterCache-Cache-your-count)和链接到插件,它将使其与habtm(http://bakery.cakephp.org/articles/view/counter-cache-behavior-for-habtm-relations)一起使用

答案 3 :(得分:0)

哈金的方式:

如果你可以拥有第三个DB字段(如上所述),那么执行一个UNIQUE的varchar(32),它是前两个的MD5哈希值。

您必须将所有保存修改为$md5_unique_field = md5( $field_one.$field_two );

CakePHP可能允许自定义验证或自定义模型扩展。

我同意这也应该在数据库级别强制执行,但CakePHP应该捕获错误。