mysql - 在 CakePHP 3 中进行深度 notMatching() 关联的正确方法是什么
问题描述
当用户的 id 为 2(或其他数字)时,我试图获取在 UsersTitles 表中没有相关记录的游戏,但我得到了所有游戏。
控制器:
$this->loadModel('Games');
$games = $this->Games->find()->notMatching('Titles.TitlesUsers', function ($q){
return $q->where(['TitlesUsers.user_id'=> 2]);
})->distinct(['Games.id']);
游戏桌
class GamesTable {
$this->hasMany('Titles', [
'foreignKey' => 'game_id',
'dependent' => true
]);
}
标题表
class TitlesTable {
$this->belongsTo('Games', ['dependent' => false]);
$this->hasMany('TitlesUsers', [
'classname' => 'TitlesUsers',
'foreignKey' => 'title_id',
'dependent' => true
]);
}
TitlesUsers 表
class TitlesUsersTable {
$this->belongsTo('Titles',['dependent'=>false]);
$this->belongsTo('Users',['dependent'=>false]);
}
游戏表内容
id | name
---|---------
1 | "Test A"
2 | "Test B"
3 | "Test C"
标题表内容
id | game_id
---|---------
1 | 1
2 | 1
3 | 1
4 | 2
5 | 2
6 | 2
7 | 3
8 | 3
9 | 3
TitlesUsers 表内容
id | title_id | user_id
---|----------|---------
1 | 1 | 2
生成的 SQL
SELECT
Games.id AS `Games__id`,
Games.name AS `Games__name`
FROM
games Games
LEFT JOIN titles Titles ON Games.id = (Titles.game_id)
LEFT JOIN titles_users TitlesUsers ON (
TitlesUsers.user_id = 2
AND Titles.id = (TitlesUsers.title_id)
)
WHERE
(TitlesUsers.id) IS NULL
GROUP BY
Games.id
如果我对直接相关的表执行 notMatching() ,它可以正常工作。当我试图获得深层 notMatching() 关联时,就会出现问题。
解决方案
这是预期的结果,在您的设置中,每个游戏组有 3 个标题,并且只有一个标题分配了用户,这意味着用户将是所有其他标题NULL
,例如,Test A
剩下的2 个标题(TitlesUsers.id) IS NULL
将为 true .
您的非分组结果如下所示:
| Games.id | Games.name | Titles.id | Titles.game_id | TitlesUsers.id | TitlesUsers.title_id | TitlesUsers.user_id |
| -------- | ---------- | --------- | -------------- | -------------- | -------------------- | ------------------- |
| 1 | Test A | 1 | 1 | 1 | 1 | 2 |
| 1 | Test A | 2 | 1 | NULL | NULL | NULL |
| 1 | Test A | 3 | 1 | NULL | NULL | NULL |
| 2 | Test B | 4 | 2 | NULL | NULL | NULL |
| 2 | Test B | 5 | 2 | NULL | NULL | NULL |
| 2 | Test B | 6 | 2 | NULL | NULL | NULL |
| 3 | Test C | 7 | 3 | NULL | NULL | NULL |
| 3 | Test C | 8 | 3 | NULL | NULL | NULL |
| 3 | Test C | 9 | 3 | NULL | NULL | NULL |
可以看出,每个游戏组至少有一排TitlesUsers.id
是NULL
。
您要么需要重新考虑您的数据库架构和关联,或者如果您需要您的架构是这种方式,请更改您过滤事物的方式,因为notMatching()
它不适合它,例如通过测试排除您不想要的游戏至少存在来自特定用户的一个标题的游戏:
$excludedGamesQuery = $this->Games
->find()
->select(['Games.id']);
->matching('Titles.TitlesUsers', function ($q){
return $q->where(['TitlesUsers.user_id' => 2]);
})
->group(['Games.id']);
$gamesQuery = $this->Games
->find()
->where([
'Games.id NOT IN' => $excludedGamesQuery
]);
推荐阅读
- php - wordpress插件下载监控器将我们通过它上传的数据存储在哪里?
- node.js - mongoose count 查询耗时过长,需要减少时间
- css - 在 React 中更改字体大小而不遇到最大“超出最大更新深度”
- angular - Angular 编译器和入口组件
- angularjs - 从工厂传播范围事件
- node.js - 节点中的日期格式以生成pdf
- javascript - Vue.js - 单击按钮时在文本区域中淡入/淡出文本
- android - 如何创建像 Android 输入一样的托盘形底部边框?
- java - Android RadioButton 仅显示文本,而不是设备模拟器中的实际按钮
- python - 每当使用python本地更新到100个开发人员时,如何从远程服务器实时流式传输大型日志文件