Orm 在CakePHP中,定义同步的方法在两个模型之间有多个和一个关联?
在CakePHP框架中,我长期以来遇到的一个问题是,在两个模型之间同时定义Orm 在CakePHP中,定义同步的方法在两个模型之间有多个和一个关联?,orm,cakephp,has-many,has-one,Orm,Cakephp,Has Many,Has One,在CakePHP框架中,我长期以来遇到的一个问题是,在两个模型之间同时定义hasOne和hasMany关系。例如: BlogEntry有很多评论 bloggentry有一条MostRecentComment(其中MostRecentComment是带有最近创建的字段的注释) 在BlogEntry模型属性中定义这些关系是有问题的。CakePHP的ORM实现了一个has-one关系作为一个内部连接,因此,只要有多个注释,BlogEntry::find('all')调用就会为每个BlogEntry返回
hasOne
和hasMany
关系。例如:
BlogEntry有很多评论
bloggentry有一条MostRecentComment
(其中MostRecentComment
是带有最近创建的字段的注释
)
在BlogEntry模型属性中定义这些关系是有问题的。CakePHP的ORM实现了一个has-one关系作为一个内部连接
,因此,只要有多个注释,BlogEntry::find('all')
调用就会为每个BlogEntry返回多个结果
我过去曾以几种方式处理过这些情况:
使用模型回调(有时,甚至在控制器或视图中!),我用:
$this->data['MostRecentComment']=$this->data['Comment'][0]代码>
如果,比如说,我需要通过Comment.created
以外的任何方式对注释进行排序,这会很快变得难看。它也不会将内置的分页功能用于按MostRecentComment字段排序(例如,按MostRecentComment.created
按逆时间顺序排序博客条目结果)
维护一个额外的外键,BlogEntry。最新的评论id
。这很烦人,并且打破了Cake的ORM:其含义是BlogEntry属于最新的评论
。它可以工作,但看起来……错了
这些解决方案还有很多不尽如人意的地方,所以前几天我坐下来研究这个问题,并制定了一个更好的解决方案。我在下面发布了我的最终解决方案,但我会很激动(也许只是有点尴尬)发现有一个让我大吃一惊的简单解决方案,我一直没有找到。或者任何其他符合我标准的解决方案:
- 它必须能够在
Model::find
级别按MostRecentComment字段进行排序(即,不仅仅是结果信息)
- 在
评论
或博客条目
表中不需要额外的字段
- 它应该尊重CakePHP ORM的“精神”
(我也不确定这个问题的标题是否尽可能简洁/信息丰富。)我开发的解决方案如下:
class BlogEntry extends AppModel
{
var $hasMany = array( 'Comment' );
function beforeFind( $queryData )
{
$this->_bindMostRecentComment();
return $queryData;
}
function _bindMostRecentComment()
{
if ( isset($this->hasOne['MostRecentComment'])) { return; }
$dbo = $this->Comment->getDatasource();
$subQuery = String::insert("`MostRecentComment`.`id` = (:q)", array(
'q'=>$dbo->buildStatement(array(
'fields' => array( String::insert(':sqInnerComment:eq.:sqid:eq', array('sq'=>$dbo->startQuote, 'eq'=>$dbo->endQuote))),
'table' => $dbo->fullTableName($this->Comment),
'alias' => 'InnerComment',
'limit' => 1,
'order' => array('InnerComment.created'=>'DESC'),
'group' => null,
'conditions' => array(
'InnerComment.blog_entry_id = BlogEntry.id'
)
), $this->Comment)
));
$this->bindModel(array('hasOne'=>array(
'MostRecentComment'=>array(
'className' => 'Comment',
'conditions' => array( $subQuery )
)
)),false);
return;
}
// Other model stuff
}
概念很简单。\u bindMostRecentComment
方法定义了一个标准,它有一个关联,在关联条件中使用一个子查询,以确保只有最新的注释连接到BlogEntry查询。该方法本身在任何模型::find()之前被调用
calls,每个博客条目的最新评论都可以过滤或排序
我意识到在hasOne
类成员中定义这种关联是可能的,但我必须编写一堆原始SQL,这让我停顿了一下
我宁愿从BlogEntry的构造函数调用\u bindMostRecentComment
,但是(根据文档)使绑定永久化的Model::bindModel()参数似乎不起作用,因此绑定必须在beforeFind回调中完成