简而言之问题
我想通过模型 B 的控制器中的 find() 操作从模型 A中检索到 HABTM模型 B的数据,而不依赖于广泛的递归。
$this->ModelB->bindModel('hasMany' => array('ModelAsModelBs'));
$this->ModelB->find('all', array('fields' => array('ModelA.*'))); //cond'ts below
我知道执行此操作需要 bindModel() ,但如果没有多次递归,我似乎无法访问关联的模型字段(即不仅是 HABTM 表的字段,还有实际的关联模型)。
我突然想到,我也可能从根本上误解了关于模型关系应该如何交互、设计或检索等方面的一些东西——简而言之,我认识到我可能不成功的原因是这可能不是我应该做的事情,哼。如果是这样,我同样很乐意学习如何做得更好,因为我经常处理非常复杂的模型关系(我主要为学术界和在线课程材料/远程研究进行网络开发)。
具体例子/实际情况
数据库有这些表,id 和你期望的一样:
- 用户
- 培训班
- 模块
- 用户课程
- 用户模块
- 课程模块
我尝试执行的模型查询发生在Users
控制器内,如下所示:
class Users extends AppController {
public function doSomething() {
$hasOne = array( 'hasOne' => array('CoursesModules','UsersModules'));
$this->User->Course->Module->bindModel($hasOne);
$conditions = array('`CoursesModules`.`course_id`' => $courseIds, //this is a known constraint within the app
'NOT' => array('`UsersModules`.`module_id` = `CoursesModules`.`module_id`' ));
$options = array( 'fields' => array('Module', 'Course.*'), // Note the attempt to get Course model information
'conditions' => $conditions,
'recursive' => 0);
$modules = $this->User->Course->Module->find('all', $options);
$this->set(compact('modules'));
}
}
此查询导致:
错误: SQLSTATE [42S02]:未找到基表或视图:1051 未知表“课程”
但我也不能bindModel()
用来连接Courses
到Modules
. 这让我觉得很奇怪,因为关联路径是Users->Courses->Modules
. 我可以将递归提高一个档次,但它会导致各种需要大量数据的地狱,unbind()
并且还会提取完全荒谬的数据量。
第二个奇怪的地方是,如果我Course.*
从字段列表中删除,上面的查询会执行,但不会像我预期的那样工作;我认为这是正确地要求 CoursesModules 中列出的所有模块,这些模块也不在UsersModules中。此类数据确实存在于我的记录中,但并未由此检索。
我意识到我可以从中获取course_ids
,CoursesModules
然后再进行一次查找以获取 Course 模型数据,但这 a) 不是很像 Cake,b) 很痛苦,因为我非常感谢能够访问$modules['Module']['Course']
渲染的视图文件。
谁能在这里指出我正确的方向?或者,哈哈,上帝保佑,帮我构建这个 MySQL 查询(我都是 MySQL 连接的大拇指)?真心感谢,谢谢!
更新
@Kai:为了建立关系,我设置了我的桌子并烤了它们。也许值得注意的是,我对 MySQL 有相当基本的了解,并且通常通过 PhpMyAdmin 完成所有工作。至于生成初始的 Cake 文件,我使用cake bake all
然后修改了一些东西。$hasAndBelongsToMany
最后发布了来自各个模型的表和数组的 SQL 。
至于我为什么选择hasOne
……我也假设hasMany
;使用这种关系总是会从我绑定的表中生成“未找到列”错误(与哪一列无关)。同时,在一定程度上,明显错误的选择hasOne
奏效了。
最后,我有一个潜伏的怀疑,这个containable behavior
行业可能是我所追求的,但我并不真正理解它。尽我所能,这是这些模型的上下文以及我尝试执行的各种查询:
我正在为大学教员构建一个程序,该程序基本上可以让教授进行一些在线课程。但是课程作业(即模块)可能在不同的班级(即课程)之间共享,学生可能在任何或所有班级。另一个限制是学生可以选择她将在给定课程中学习哪些模块——教授可能会提供其中五个,他们必须完成其中的三个。因此,当学生登录时,我需要能够在他们所在课程的上下文中检索他们尚未完成的模块。
我必须提出大量类似的查询,这些查询或多或少属于这种性质。就目前而言,我可以通过各种使用来实现所有这一切(因为这是在最后期限内完成的)loadModel()
,执行更简单$this->Model->find()
的,通过一些逻辑对结果进行排序foreach
,冲洗重复。除了烦人之外,我还担心由于我的处理不当,它无法扩展,最后......我讨厌做错事,哈哈。我知道 CakePHP 可以处理我想问我的数据的问题,我只是不知道如何问他们(和/或设置数据以便可以问这样的问题)。
CREATE TABLE IF NOT EXISTS `modules` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`domain_id` int(11) NOT NULL,
`subject_id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`description` text NOT NULL,
`passing_score` int(11) NOT NULL,
`max_attempts` int(11) NOT NULL,
`allow_retry` int(11) NOT NULL,
`running_score` tinyint(1) NOT NULL,
`score_privacy` int(11) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `domain_id` (`domain_id`),
KEY `subject_id` (`subject_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`group_id` int(11) NOT NULL,
`institution_id` int(11) NOT NULL,
`password` varchar(255) NOT NULL,
`firstname` varchar(63) NOT NULL,
`lastname` varchar(63) NOT NULL,
`email` varchar(255) NOT NULL,
`studentno` varchar(31) NOT NULL,
`claimed` tinyint(1) NOT NULL,
`verified` tinyint(1) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `group_id` (`group_id`),
KEY `institution_id` (`institution_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `courses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`institution_id` int(11) NOT NULL,
`coursecode` varchar(255) NOT NULL,
`name` varchar(255) NOT NULL,
`semester` varchar(7) NOT NULL,
`educator_id` int(11) NOT NULL,
`year` year(4) NOT NULL,
`description` text NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`educator_id`), /* educator is an alias of user in some cases */
KEY `institution_id` (`institution_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `users_courses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`course_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`,`course_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `users_modules` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`module_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`,`module_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
CREATE TABLE IF NOT EXISTS `courses_modules` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`course_id` int(11) NOT NULL,
`module_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `course_id` (`course_id`,`module_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
模型协会
注意:这并不全面——hasOne、hasMany、belongsTo 等。已省略以节省空间;如果需要,我可以发布整个模型。
// from User Model
public $hasAndBelongsToMany = array(
'Course' => array(
'className' => 'Course',
'joinTable' => 'users_courses',
'foreignKey' => 'user_id',
'associationForeignKey' => 'course_id',
'unique' => 'keepExisting',
),
'Module' => array(
'className' => 'Module',
'joinTable' => 'users_modules',
'foreignKey' => 'user_id',
'associationForeignKey' => 'module_id',
'unique' => 'keepExisting',
)
);
// from Course Model
public $hasAndBelongsToMany = array(
'Module' => array(
'className' => 'Module',
'joinTable' => 'courses_modules',
'foreignKey' => 'course_id',
'associationForeignKey' => 'module_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
),
'User' => array(
'className' => 'User',
'joinTable' => 'users_courses',
'foreignKey' => 'course_id',
'associationForeignKey' => 'user_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
)
);
// from Module Model
public $hasAndBelongsToMany = array(
'Excerpt' => array(
'className' => 'Excerpt',
'joinTable' => 'excerpts_modules',
'foreignKey' => 'module_id',
'associationForeignKey' => 'excerpt_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
),
'Course' => array(
'className' => 'Course',
'joinTable' => 'courses_modules',
'foreignKey' => 'module_id',
'associationForeignKey' => 'course_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
)
);