即使我指定了外键,CakePHP 3 仍使用主键 (setPrimaryKey) 执行 JOIN

CakePHP 3 is using primary key (setPrimaryKey) to do a JOIN even though I've specified a foreign key

CakePHP 3.7

我有2个型号Table 类如下:

  1. /src/Model/Table/SubstancesTable.php
  2. /src/Model/Table/TblOrganisationSubstancesTable.php

MySQL 中每个 table 的架构如下:

1.

mysql> describe substances;
+-------------+-----------------------+------+-----+---------+----------------+
| Field       | Type                  | Null | Key | Default | Extra          |
+-------------+-----------------------+------+-----+---------+----------------+
| id          | mediumint(8) unsigned | NO   | PRI | NULL    | auto_increment |
| app_id      | varchar(8)            | NO   | UNI | NULL    |                |
| name        | varchar(1500)         | NO   |     | NULL    |                |
| date        | date                  | NO   |     | NULL    |                |
+-------------+-----------------------+------+-----+---------+----------------+

2.

mysql> describe tbl_organisation_substances;
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| o_sub_id    | int(255)     | NO   | PRI | NULL    | auto_increment |
| o_id        | int(255)     | NO   | MUL | NULL    |                |
| app_id      | varchar(15)  | YES  |     | NULL    |                |
| os_name     | varchar(255) | YES  |     | NULL    |                |
| ec          | varchar(35)  | YES  |     | NULL    |                |
| cas         | varchar(255) | YES  |     | NULL    |                |
| upload_id   | int(100)     | YES  |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+

我编写了一个自定义查找器,它需要在这 2 个 table 之间执行 JOIN。自定义查找器看起来像这样,位于 SubstancesTable.php:

public function findDistinctSubstancesByOrganisation(Query $query, array $options)
{
    $o_id = $options['o_id'];

    $query = $this->find()->select('id')->contain('TblOrganisationSubstances')->where(['TblOrganisationSubstances.o_id' => $o_id]);

    return $query;
}

每个 table 都有一个 app_id 列,这是链接 2 table 的外键。

最初我收到一个错误:

The TblOrganisationSubstances association is not defined on Substances.

这是有道理的,因为尚未制定任何定义。

所以在 SubstancesTable.php 中我定义了这个:

$this->setPrimaryKey('id');

// ...

$this->belongsTo('TblOrganisationSubstances', [
    'foreignKey' => 'app_id',
    'joinType' => 'INNER'
]);

但这会产生以下 SQL 语句:

SELECT Substances.id AS `Substances__id` FROM substances Substances INNER JOIN tbl_organisation_substances TblOrganisationSubstances ON TblOrganisationSubstances.o_sub_id = (Substances.app_id) WHERE TblOrganisationSubstances.o_id = :c0

这是行不通的,因为 TblOrganisationSubstances.o_sub_id = (Substances.app_id) 是错误的。需要根据app_id进行JOIN,也就是说应该是:

TblOrganisationSubstances.app_id = (Substances.app_id)

我还尝试将 belongsTo 更改为 hasMany 关联(甚至不确定哪个是正确的!):

$this->hasMany('TblOrganisationSubstances', [
    'foreignKey' => 'app_id',
]);

但加入似乎甚至没有发生。产生的SQL是:

SELECT Substances.id AS `Substances__id` FROM substances Substances WHERE TblOrganisationSubstances.o_id = :c0

我也试过在TblOrganisationSubstances.php中放一个belongsTo来尝试定义双方的关系:

$this->belongsTo('Substances', [
    'foreignKey' => 'app_id',
    'joinType' => 'INNER'
]);

同样,这不起作用。它在没有连接的情况下生成 SQL。

请有人帮忙建议哪种关联类型是正确的(hasMany vs belongsTo)以及如何根据 app_id 执行连接,这是链接 2 tables.

的外键

BelongsTo 关联中,source table 持有外键,因此根据您的配置,它将在 Substances,并与TblOrganisationSubstances.

的主键进行比较

为了得到你正在寻找的查询,你还必须定义bindingKey,即目标的外键table,这样它就不会使用它的主键:

$this->belongsTo('TblOrganisationSubstances', [
    'foreignKey' => 'app_id', // Substances.app_id
    'bindingKey' => 'app_id', // TblOrganisationSubstances.app_id
    'joinType' => 'INNER'
]);

HasMany 还是 BelongsTo 取决于您的数据,以及您想要检索数据的内容和方式。一般如果一个Substances有0个或1个TblOrganisationSubstances1:1),那么就是BelongsToHasOne。如果一个Substances可以有多个TblOrganisationSubstances1:n),那么就是HasMany.

如果您想按 HasMany 关联进行过滤,则需要使用匹配或连接(matching()innerJoinWith()leftJoinWith()),因为 HasMany 相关记录将在使用 contain().

时在单独的查询中检索

另见

SELECT * FROM sample LEFT JOIN user ON sample.rac_id=user.userrac_id UNION ALL SELECT * FROM sample RIGHT JOIN user ON sample.rac_id=user.userrac_id

    public $hasAndBelongsToMany = array(
        'Ingredient' =>
            array(
                'className' => 'Ingredient',
                'joinTable' => 'ingredients_recipes',
                'foreignKey' => 'recipe_id',
                'associationForeignKey' => 'ingredient_id',
                'unique' => true,
                'conditions' => '',
                'fields' => '',
                'order' => '',
                'limit' => '',
                'offset' => '',
                'finderQuery' => '',
                'with' => ''
            )
    );
}````