У меня возникли проблемы с включением второй базы данных в мое приложение.
app.php
и app_local.php
.BusinessRequests
), ссылающаяся на вторую базу данных, реализует defaultConnectionName()
Ошибка:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'app_a.business_requests' doesn't exist
Результирующий SQL – обратите внимание на отсутствие префикса базы данных/соединения при ссылке на BusinessRequests
в LEFT JOIN.
SELECT
Requests.id AS Requests__id,
Requests.business_request_id AS Requests__business_request_id,
Requests.notes AS Requests__notes,
Requests.created AS Requests__created,
Requests.modified AS Requests__modified,
BusinessRequests.id AS BusinessRequests__id,
BusinessRequests.title AS BusinessRequests__title,
BusinessRequests.status AS BusinessRequests__status,
BusinessRequests.created AS BusinessRequests__created,
BusinessRequests.modified AS BusinessRequests__modified
FROM
requests Requests
LEFT JOIN business_requests BusinessRequests ON BusinessRequests.id = Requests.business_request_id
WHERE
Requests.id = 1
LIMIT
1
База данных app_a
(обратите внимание на настройку внешнего ключа)
CREATE TABLE `requests` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`business_request_id` int(11) unsigned DEFAULT NULL,
`notes` varchar(255) NOT NULL,
`created` datetime NOT NULL DEFAULT current_timestamp(),
`modified` datetime NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
KEY `FK_requests_app_common.business_requests` (`business_request_id`),
CONSTRAINT `FK_requests_app_common.business_requests` FOREIGN KEY (`business_request_id`) REFERENCES `app_common`.`business_requests` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci
База данных app_common
CREATE TABLE `business_requests` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`status` varchar(255) NOT NULL,
`created` datetime NOT NULL DEFAULT current_timestamp(),
`modified` datetime NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=70270 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci
Содержание app.php
'Datasources' => [
'default' => [
'className' => Connection::class,
'driver' => Mysql::class,
'persistent' => false,
'timezone' => 'UTC',
'flags' => [],
'cacheMetadata' => true,
'log' => false,
'quoteIdentifiers' => false,
],
'common' => [
'className' => Connection::class,
'driver' => Mysql::class,
'persistent' => false,
'timezone' => 'UTC',
'flags' => [],
'cacheMetadata' => true,
'log' => false,
'quoteIdentifiers' => false,
],
],
Содержимое app_local.php
(mariadb — это Docker-контейнер)
'Datasources' => [
'default' => [
'host' => 'mariadb',
'username' => 'root',
'password' => 'root',
'database' => 'app_a',
'url' => env('DATABASE_URL', null),
],
'common' => [
'host' => 'mariadb',
'username' => 'root',
'password' => 'root',
'database' => 'app_common',
'url' => env('DATABASE_URL', null),
],
],
Содержание BusinessRequestsTable.php
Здесь я указываю соединение, которое будет использоваться для модели.
public static function defaultConnectionName(): string
{
return 'common';
}
Содержание RequestsController.php
public function view($id = null)
{
$request = $this->Requests->get($id, [
'contain' => ['BusinessRequests'],
]);
$this->set(compact('request'));
}
Тогда мне просто нужно убедиться, что в другой базе данных прочитано текущее соединение по умолчанию?
Странный. Если я оставлю $this->setTable(Configure::read('br_db_name').'.business_requests');
, но удалю соединение common
и defaultConnectionName()
из модели, это не сработает: Table 'app_a.business_requests' doesn't exist
Если к обеим базам данных можно получить доступ через одно и то же соединение (т. е. один и тот же сервер + одни и те же учетные данные), это правильный путь. Однако я не могу сказать вам, поддерживает ли его CakePHP/4 (в последний раз я использовал фреймворк в более ранней версии, которая не поддерживала).
Старый запрос на добавление функции . Тогда он не был реализован, но содержит хорошие идеи.
Укажите в запросе, какая таблица какой базе данных принадлежит. Попробуйте что-то вроде этого:
SELECT
Requests.id AS Requests__id,
Requests.business_request_id AS Requests__business_request_id,
Requests.notes AS Requests__notes,
Requests.created AS Requests__created,
Requests.modified AS Requests__modified,
BusinessRequests.id AS BusinessRequests__id,
BusinessRequests.title AS BusinessRequests__title,
BusinessRequests.status AS BusinessRequests__status,
BusinessRequests.created AS BusinessRequests__created,
BusinessRequests.modified AS BusinessRequests__modified
FROM
app_a.requests Requests
LEFT JOIN app_common.business_requests BusinessRequests ON BusinessRequests.id = Requests.business_request_id
WHERE
Requests.id = 1
LIMIT
1
Как мне настроить префикс базы данных для включения в запрос? В находке? Модель может быть?
В этом случае установка префикса базы данных (т. е. app_common
) при настройке таблицы в модели, похоже, решила проблему.
public function initialize(array $config): void
{
parent::initialize($config);
$this->setTable('app_common.business_requests');
$this->setDisplayField('title');
$this->setPrimaryKey('id');
$this->addBehavior('Timestamp');
}
Вы не можете объединять таблицы из разных соединений, если вы это пытаетесь сделать. Запрос будет отправлен на сервер MariaDB и обработан там, сервер ничего не знает о других соединениях, которые мог установить клиент. Соединения независимы; им даже не обязательно принадлежать одному и тому же серверу.