2

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

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

反之亦然,但唯一标志对我没有帮助;我仍然可以为同一对夫妇节省两次。

我如何在 CakePHP 中做到这一点?我应该直接在数据库中声明这对夫妇(书,标签)是唯一的,还是这会让 CakePHP 发疯?有没有一种 Cakey 方法来处理这种情况?

编辑:我尝试通过查询使这对夫妇独一无二(我正在使用 MySQL)

ALTER TABLE books_tags ADD UNIQUE (book_id,tag_id);

但这并不好。当我一次保存多个标签时,如果所有情侣都是新的,一切都会顺利进行。如果至少有一对重复,CakePHP 将无法完成整个操作,因此它不会保存任何新的一对(即使是好的一对)。

4

4 回答 4

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'
    )
);

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

于 2010-03-08T02:09:00.867 回答
1

在我看来,任何时候您有数据需求,都应该在数据(基础)级别指定这些需求。在尽可能低的级别执行您的规则。如果应用程序也可以执行这些规则,并且您选择这样做,那么我会说它不会受到伤害。不过,我建议不要将应用程序用作强制数据约束的唯一手段。

于 2010-03-07T15:04:19.877 回答
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 )

于 2010-03-07T16:21:43.377 回答
0

黑客方式:

如果您可以拥有第三个数据库字段(如上面的那个),请执行一个 VARchar(32),它是唯一的,它是前两个的 MD5 散列。

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

CakePHP 可能允许自定义验证或自定义模型扩展来自动执行此操作。

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

于 2010-03-07T21:18:15.503 回答