0

私は、外部の(そして完全に変更できない)ソースからインポートされたデータを持つアプリケーションに取り組んでいます。問題を説明するために、いくつかの表を簡略化します。以下は、主キーのある表です。

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)

したがって、請求書、ヘッダー、および配信には1対1の関係があることがわかります。請求書からトランザクションおよび請求書からメッセージは1対多です。

idこれらのテーブルを自分のデータベースにインポートする際に、既存の主キーを一意のキーに変更し、各テーブルにauto_incrementingフィールド()を追加しました。

ここで問題となるのは、Cakeでリレーションシップを設定することです。これは、Cakeが実際には複合キーをまったく処理しないためです。私は1対1の関係を次のように機能させることができました:

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"
                )
            )
         )
    ;
}

そして、これは機能します。これは、1対1の関係が、大きなLEFTJOINを使用して一度に照会されるためです。Cakeは2つのクエリを実行するため、1対多の関係(たとえば、請求書とトランザクション)で同じ方法を試行すると、1つ目は一致するすべての請求書を検索し、2つ目は対応する外部のすべてのトランザクションを検索するために終了します。最初のクエリの結果と一致するキー:(実行しようとしている簡略化されたクエリは次のとおりです)

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`

ご覧のとおり、請求書に結合されていないため、クエリは終了します。

これを機能させる方法について何かアイデアはありますか?

4

2 に答える 2

1

最悪のシナリオでは、hasMany 関係の finderQuery パラメーターを使用できます。これにより、クエリを完全にオーバーライドできます。

関連するデータ フィールドを 1 つに結合する一意の ID フィールドを追加することもできます。データベースがトリガーをサポートしていると仮定すると、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->Transaction が定義されるように、直接使用しない場合でも、Invoice と Transaction との定義済みの関係が必要であることを忘れないでください。

また、データが hasMany 関係のように返されるようにしたい場合は、常に foreach ループを追加して、そのように再結合することができます。

更新Cake Bakeryには、通常の hasMany 関連付けの形式で他のテーブルからこれらの結果を簡単に返すことができるSimpleResults 動作 もあります。

于 2009-10-30T06:32:38.307 に答える
0

http://bakery.cakephp.org/articles/view/quick-tip-doing-ad-hoc-joins-in-model-find

于 2009-11-03T17:29:14.883 に答える