在CakePHP 3中做深度notMatching()关联的正确方法是什么

hc8w905p  于 2022-11-12  发布在  PHP
关注(0)|答案(1)|浏览(129)

当用户的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
  ]);    
}

标题用户表

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

标题用户表内容

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()关联时,问题出现了。

o4tp2gmn

o4tp2gmn1#

这是预期的结果,在您的设置中,每个游戏组有3个标题,只有其中一个标题分配了用户,这意味着对于所有其他标题,用户将是NULL,例如,Test A还有2个标题,(TitlesUsers.id) IS NULL将为真。
未分组的结果将如下所示:

| 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.idNULL
您需要重新考虑数据库模式和关联,或者如果您需要这样的模式,则更改过滤内容的方式,因为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
    ]);

相关问题