CakePHP 3 использует первичный ключ (setPrimaryKey), чтобы выполнить JOIN, даже если я указал внешний ключ - PullRequest
0 голосов
/ 15 октября 2019

CakePHP 3.7

У меня есть 2 модели Таблицы классов следующим образом:

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

Схема для каждой таблицы в MySQL выглядит следующим образом:

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    |                |
+-------------+--------------+------+-----+---------+----------------+

Я написал собственный искатель, который должен выполнить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;
}

Каждая таблица имеет столбец app_id, и это внешний ключ, который связывает 2 таблицы.

Изначально яполучено сообщение об ошибке:

Не определена ассоциация TblOrganisationSubstances для веществ.

Это имело смысл, поскольку не было введено ни одного определения.

Итак, в 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, другими словами, это должно быть:

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

Я также попытался вставить belongsTo в TblOrganisationSubstances.php, чтобы попытаться определить отношения с обеих сторон:

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

Опять же, это не такт работа. Он генерирует SQL без объединения.

Пожалуйста, кто-то может помочь с советом, который является правильным типом ассоциации (hasMany против belongsTo) и как выполнить соединение на основе app_id,который является внешним ключом, связывающим две таблицы.

Ответы [ 3 ]

1 голос
/ 15 октября 2019

В ассоциации BelongsTo таблица source содержит внешний ключ, поэтому в вашей конфигурации она будет использовать app_id на Substances и сравнивать с первичным ключом TblOrganisationSubstances.

Чтобы получить искомый запрос, вам также нужно определить bindingKey, т.е. внешний ключ таблицы target , чтобы он неиспользуйте его первичный ключ:

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

Независимо от того, является ли он HasMany или BelongsTo, определяется вашими данными, а также тем, что и как вы хотите получить. Обычно, если у одного Substances есть 0 или 1 TblOrganisationSubstances (1:1), то это BelongsTo или HasOne. Если один Substances может иметь более 1 TblOrganisationSubstances (1:n), то это HasMany.

. И если вы хотите фильтровать по ассоциации HasMany, то вам нужно использовать либосопоставление или объединение (matching(), innerJoinWith(), leftJoinWith()), поскольку HasMany связанные записи будут получены в отдельном запросе при использовании contain().

См. также

0 голосов
/ 22 октября 2019
    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' => ''
            )
    );
}````
0 голосов
/ 22 октября 2019

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

...