使HABTM关系在CakePHP中独一无二
我有两个模型,叫做Book和Tag,它们处于HABTM关系中。我想要一对(书、标签)只保存一次。在我的模型中,我有使HABTM关系在CakePHP中独一无二,php,cakephp,model,has-and-belongs-to-many,Php,Cakephp,Model,Has And Belongs To Many,我有两个模型,叫做Book和Tag,它们处于HABTM关系中。我想要一对(书、标签)只保存一次。在我的模型中,我有 var $hasAndBelongsToMany = array( 'Tag' => array( 'className' => 'Tag', 'joinTable' => 'books_tags', 'foreignKey' => 'book_id', 'associationFore
var $hasAndBelongsToMany = array(
'Tag' => array(
'className' => 'Tag',
'joinTable' => 'books_tags',
'foreignKey' => 'book_id',
'associationForeignKey' => 'tag_id',
'unique' => true
)
);
还有维切维萨,但这面独特的旗帜对我没有帮助;我仍然可以为同一对夫妇节省两倍的钱
如何在CakePHP中实现这一点?我应该直接在数据库中声明这对夫妇(书籍、标签)是唯一的,还是这会让CakePHP发疯?有没有一个关键的方法来处理这种情况
编辑:我尝试通过查询使这对夫妇唯一(我使用的是MySQL)
但这并不奏效。当我一次保存多个标签时,如果所有夫妇都是新人,一切都会顺利进行。如果至少有一对重复,CakePHP无法完成整个操作,因此它不会保存任何新的对(即使是好的对)。在我看来,任何时候有数据要求,都应该在数据(基础)级别指定这些要求。在尽可能低的级别执行规则。如果应用程序也可以执行这些规则,而您选择这样做,那么我认为这不会有什么坏处。不过,我建议不要使用应用程序作为强制执行数据约束的唯一手段。我建议您将约束放在数据库模式中。如果可以将组合列声明为主键,这将很容易,尽管我认为这会导致一些问题 根据您使用的RDBMS,您可能能够创建一个组合行索引,并在该索引上声明一个唯一的约束 为了保持这种逻辑,另一种选择是更改Book模型中的beforeSave()函数,以便它首先对传递的数据运行find(),并且只有在find返回false时才会保存(这意味着没有前一对,这意味着您已经满足了唯一的约束) 一个我不承诺会奏效的选项是CakePHP计数器缓存行为,但看起来可能会。不确定它在默认情况下是否适用于HABTM,但下面是指向蛋糕书()的链接和使其适用于HABTM()的插件的链接。Hackish way: 如果您可以使用第三个DB字段(如上面的一个),那么可以使用唯一的varchar(32),即前两个字段的MD5哈希 您必须将所有保存修改为
$md5\u unique\u field=md5($field\u one.$field\u two)代码>
CakePHP可能允许自定义验证或自定义模型扩展来自动执行此操作
不过,我同意这也应该在DB级别强制执行,CakePHP应该捕获错误。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'
)
);
如果除此之外,您还在DB级别上强制执行唯一性,那就更好了。我同意,但是如果CakePHP第二次尝试保存一对(书籍、标签)时会发生什么呢?我希望它被优雅地处理,并且不会导致错误。您肯定希望在应用程序端捕获任何数据库错误。我并不是有意要暗示,捕捉错误的逻辑确实有点复杂。当用户修改一本书,添加一些标记时,这对夫妇将被保存。因此,当CakePHP试图保存相关模型(标记)时,失败的是保存这本书。然后,我应该了解重复的内容,然后删除这些内容并再次尝试保存。这没有多大意义;更明智的做法是让程序在保存之前检查重复项。无论如何,我觉得这不是正确的方法…你能解释一下array('validate'=>'first')
在saveAll($data,array('validate'=>'first'))中的用法吗
var $hasAndBelongsToMany = array(
'Tag' => array(
...
'with' => 'BooksTag'
)
);