Работа с моделями, которые не имеют ни одного внешнего ключа в CakePHP - PullRequest
0 голосов
/ 30 октября 2009

Я работаю над приложением, данные которого импортированы из иностранного (и полностью неизменного) источника. Я упрощу некоторые таблицы, чтобы объяснить проблему. Ниже приведены таблицы с их первичными ключами.

invoices     (doc_number, date_printed, batch_number)
headers      (doc_number, date_printed, batch_number)
deliveries   (doc_number, date_printed, batch_number)
transactions (doc_number, date_printed, batch_number, line_number)
messages     (doc_number, date_printed, batch_number, line_number)

Таким образом, вы можете видеть, что Счета-фактуры, Заголовки и Доставки имеют отношения один-к-одному. Счета-фактуры к транзакциям и счета-фактуры к сообщениям - «один ко многим».

При импорте этих таблиц в мою собственную базу данных я изменил существующий первичный ключ на уникальный ключ и добавил поле auto_incrementing (id) для каждой таблицы.

Теперь проблема заключается в настройке отношений в Cake, поскольку он вообще не обрабатывает составные ключи. Мне удалось заставить отношения «один к одному» работать так:

class Invoice extends AppModel {
    public $name = "Invoice"
         , $hasOne = array(
            "Header" => array(
                'foreignKey' => false,
                'conditions' => array(
                    "Invoice.doc_number = Header.doc_number",
                    "Invoice.date_printed = Header.date_printed",
                    "Invoice.batch_number = Header.batch_number"
                )
            )
         )
    ;
}

И это работает, потому что отношения один-к-одному запрашиваются за один раз с большим левым соединением. Попытка того же метода с отношением «один ко многим» (например, со счетами и транзакциями) прекращается, потому что Cake выполняет два запроса: первый, чтобы найти все соответствующие счета, а затем второй, чтобы найти все транзакции с соответствующим внешним ключ, соответствующий результатам первого запроса: (вот упрощенный запрос, который он пытается выполнить)

SELECT `Transaction`.* FROM `transactions` AS `Transaction`
WHERE `Invoice`.`doc_number` = `Transaction`.`doc_number`
AND `Invoice`.`date_printed` = `Transaction`.`date_printed`
AND `Invoice`.`batch_number` = `Transaction`.`batch_number`

Как видите, он не включается в счета, поэтому запрос умирает.

Любые идеи о том, как я могу сделать эту работу?

Ответы [ 2 ]

1 голос
/ 30 октября 2009

В худшем случае вы можете использовать параметр finderQuery для hasMany отношения . Это позволяет полностью переопределять запросы.

Вы также можете добавить уникальное поле идентификатора, которое объединяет соответствующие поля данных в одно. Оператор UPDATE может исправить существующие данные, и TRIGGER может быть настроен для обновления новых записей по мере их добавления или изменения, при условии, что ваша база данных поддерживает триггеры.

Редактировать: Со всеми остальными сложностями вам может быть лучше вообще пропустить отношение hasMany и получить записи транзакций в отдельном find (). Если вам нужно сделать это очень много мест, вы всегда можете обернуть его в функцию в модели Invoice, например, такую:

<?php
class Invoice extends AppModel() {
    ...

    function getInvoice($conditions) {
        $invoice = $this->find('first', compact('conditions'));

        $conditions = array(
             'Transaction.doc_number' => $invoice['Invoice']['doc_number'],
             'Transaction.date_printed' => $invoice['Invoice']['date_printed'],
             'Transaction.batch_number' => $invoice['Invoice']['batch_number']);
        $invoice['transactions'] = $this->Transaction->find('all', compact('conditions'));

        return $invoice;
    }
}
?>

Если вы используете функцию, подобную этой, в модели, не забывайте, что для счета-фактуры потребуется определенное отношение к транзакции, даже если вы не используете ее напрямую, так что определяется $ this-> транзакция. *

Кроме того, если вы предпочитаете, чтобы данные возвращались так, как было бы в отношении hasMany, вы всегда можете добавить цикл foreach для их рекомбинации таким образом.

Обновление В Cake Bakery также есть поведение SimpleResults, которое позволяет легко возвращать эти результаты из другой таблицы в формате обычной ассоциации hasMany.

0 голосов
/ 03 ноября 2009
...