Question

Je travaille sur une application qui contient des données importées d'une source étrangère (et totalement non modifiable). Je vais simplifier certaines des tables pour expliquer le problème. Vous trouverez ci-dessous les tables avec leurs clés primaires.

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)

Ainsi, vous pouvez voir que les factures, les en-têtes et les livraisons ont des relations un à un. Les factures vers transactions et les factures vers messages sont un à plusieurs.

Lors de l'importation de ces tables dans ma propre base de données, j'ai modifié la clé primaire existante en une clé unique et ajouté un champ auto_incrementing ( id ) sur chaque table.

Maintenant, le problème est de configurer les relations dans Cake, car cela ne gère pas vraiment les clés composites. J'ai réussi à faire en sorte que les relations un à un fonctionnent comme suit:

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

Et cela fonctionne, car les relations un à un sont interrogées en une fois avec un gros LEFT JOIN. Essayer la même méthode avec une relation un-à-plusieurs (par exemple, avec des factures et des transactions) échoue, car Cake effectue deux requêtes: la première pour trouver toutes les factures correspondantes, puis la seconde pour trouver toutes les transactions avec une transaction étrangère correspondante. clé qui correspond aux résultats de la première requête: (voici la requête simplifiée qu'il tente d'exécuter)

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`

Comme vous pouvez le constater, les factures ne sont pas jointes et la requête meurt.

Avez-vous des idées sur la façon dont je peux faire en sorte que cela fonctionne?

Était-ce utile?

La solution

Dans le pire des cas, vous pouvez utiliser le paramètre finderQuery de la relation hasMany . Cela vous permet de remplacer complètement les requêtes.

Vous pourriez également être en mesure d'ajouter un champ d'identifiant unique qui combine les champs de données pertinents en un seul. Une instruction UPDATE pourrait corriger les données existantes et TRIGGER pourrait être configuré pour mettre à jour de nouveaux enregistrements à mesure qu’ils sont ajoutés ou modifiés, en supposant que votre base de données prenne en charge les déclencheurs.

Modifier: Avec toutes les autres complexités, il vaudrait peut-être mieux ignorer la relation hasMany et récupérer les enregistrements de transaction dans une recherche distincte (). Si vous devez le faire à de nombreux endroits, vous pouvez toujours l’envelopper dans une fonction du modèle de facturation comme celle-ci:

<?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;
    }
}
?>

Si vous utilisez une fonction comme celle-ci dans le modèle, n'oubliez pas que Invoice aurait besoin d'une relation définie avec Transaction, même si vous ne l'utilisez pas directement, de sorte que $ this- > Transaction est défini.

De même, si vous préférez que les données soient renvoyées comme le serait une relation hasMany, vous pouvez toujours ajouter une boucle foreach pour les recombiner de cette façon.

Mettre à jour Il existe également un comportement SimpleResults dans la pâtisserie Cake Bakery qui permettrait de renvoyer facilement les résultats de l’autre tableau au format d’une association hasMany classique.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top