我是cakephp可容纳元素的忠实粉丝,因为我一直认为,它会处理适当的其他模型的加载。但在最后几天,我深入挖掘并发现,确实存在记忆问题。
考虑以下模型结构:
反之亦然
在墙控制器中,我有以下find-Statement:
$this->set(
"posts",
$this->Post->find(
"all", array(
"conditions" => array("Post.wall_id" => $wall["Wall"]["id"]),
"contain" => array("Participant")
)
)
);
我希望,cakephp会找到所有帖子,只包含相应的参与者对象。但是,我得到的是所有帖子的列表(正确)&他们的参与者(正确),但也相应的墙(不正确)&相应的评论,如果可用(不正确)。所以从性能的角度来看:太多的对象,这可能导致“致命的错误 - 内存过载”。
而对于,理论上真正性感的&有趣的部分:
$this->set(
"posts",
$this->Post->find(
"all", array(
"conditions" => array("Post.wall_id" => $wall["Wall"]["id"]),
"contain" => array("Participant.User")
)
)
);
因为我只对Post&amp ;;感兴趣 Participant.User 对象,我将包含数组更改为Participant.User。但是,现在我不仅要获得User对象,还要获得参与者的所有其他相关对象(项目,帖子,评论......),并且对象树比以前大得多。
所以我想知道,实现这个的正确方法是什么?我是否需要显式设置“join”选项,还是必须设置fields选项(在root或者contains-option中)?
来自奥地利的问候。
答案 0 :(得分:1)
停止使用Containable。它确实会生成太多查询。使用joins
语法。请查看this问题和食谱article。
<强>更新强>
在SQL中,您可以使用JOIN
语句组合相关表。这允许您跨多个表执行复杂搜索(即:给出多个标签的搜索帖子)。
在CakePHP中,一些关联(belongsTo
和hasOne
)执行自动连接以检索数据,因此您可以发出查询以根据相关数据中的数据检索模型。
但hasMany
和hasAndBelongsToMany
关联并非如此。这是强迫联接来救援的地方。您只需定义必要的联接以组合表并获得所需的查询结果。
请记住,您需要将递归设置为-1
才能生效。我:$this->Channel->recursive = -1;
要强制表之间的连接,您需要使用Model::find()
的“现代”语法,向‘joins’
数组添加$options
键。例如:
$options['joins'] = array(
array('table' => 'channels',
'alias' => 'Channel',
'type' => 'LEFT',
'conditions' => array(
'Channel.id = Item.channel_id',
)
)
);
$Item->find('all', $options);
请注意,‘join’
数组不是键控的。
在上面的例子中,名为Item的模型保持连接到channels表。您可以使用Model名称对表进行别名,以便检索的数据符合CakePHP数据结构。
定义连接的键如下:
table
:联接表。alias
:表格的别名。与表关联的模型的名称是最好的选择。type
:联接类型:内部,左侧或右侧。conditions
:执行加入的条件。使用联接,您可以根据相关模型字段添加条件:
$options['joins'] = array(
array('table' => 'channels',
'alias' => 'Channel',
'type' => 'LEFT',
'conditions' => array(
'Channel.id = Item.channel_id',
)
)
);
$options['conditions'] = array(
'Channel.private' => 1
);
$privateItems = $Item->find('all', $options);
您可以根据需要在hasBelongsToMany中执行多个连接:
假设书籍hasAndBelongsToMany
标签关联。此关系使用books_tags表作为连接表,因此您需要将books表连接到books_tags表,并使用tags表连接:
$options['joins'] = array(
array('table' => 'books_tags',
'alias' => 'BooksTag',
'type' => 'inner',
'conditions' => array(
'Books.id = BooksTag.books_id'
)
),
array('table' => 'tags',
'alias' => 'Tag',
'type' => 'inner',
'conditions' => array(
'BooksTag.tag_id = Tag.id'
)
)
);
$options['conditions'] = array(
'Tag.tag' => 'Novel'
);
$books = $Book->find('all', $options);
使用具有可包含行为的联接可能会导致一些SQL错误(重复的表),因此如果您的主要目标是基于相关数据执行搜索,则需要使用联接方法作为Containable的替代方法。 Containable最适合限制find语句带来的相关数据量。
答案 1 :(得分:0)
理论上,这应该可以正常工作。确保已设置
var $actsAs = array('Containable');
您正在引用的每个模型。
编辑:仔细观察,也许不是。请尝试以下方法......
$this->set(
"posts",
$this->Post->find(
"all", array(
"conditions" => array("Post.wall_id" => $wall["Wall"]["id"]),
"contain" => array("Participant" => array("User"))
)
)
);
答案 2 :(得分:0)
这是否有助于:
$this->loadModel('Participant');
$this->Participant->bindModel(array(
'belongsTo' => array(
'User' => array(
'className' => 'Wish',
'foreignKey' => 'user_id'
)
)
),0);
$this->set( "posts", $this->Post->find( "all", array( "conditions" => array("Post.wall_id" => $wall["Wall"]["id"]), "contain" => false ) ) );
答案 3 :(得分:0)
我在我的一个项目中使用ContainableBehaviour,即使有大量关系,它也能正常工作。我认为由于以下关系,它在您的情况下无法正常工作:
为什么参与者属于帖子? 为什么参与者属于评论?
当你摆脱这些关系时,是否包含了预期的工作?
如果您需要这些所有这些关系,并且已正确设置HABTM关系。检查this post,其中解释了如何使用HABTM关系使用ContainableBehaviour。
答案 4 :(得分:0)
我从未使用过Dot Syntax。 你试过吗
"contain" => array('Participant'=>array('User'))
对我而言,似乎无法以某种方式附加可包含的行为。 你是如何附加/激活你的行为的?
答案 5 :(得分:0)
我一直在解决同样的问题然后我发现在某些模型中我设置了afterFind回调并在另一个SQL查询中,这使得可容纳的行为变得混乱。 所以我建议在回调中将内部查询重写为纯SQL,对我有帮助,并解决了可包含的链接。
答案 6 :(得分:0)
首先要做的是在你的父模型中,将礼节递归设置为-1
$this->recursive = -1;
通过做蛋糕将只加载我们在包含array()中设置的模型。
感谢