2010-10-19 32 views
1

J'ai défini ces relations dans mes modèles:Pourquoi CakePHP duplique-t-il mes requêtes? (Ce n'est pas le même "trop ​​de requêtes" problème qui est habituellement demandé)

Lead hasMany Job
Job HABTM employé
emploi HABTM Camion

Je suis en train de faire un find('all') de mon modèle de camion, et limiter les résultats à:

  1. tous les camions,
  2. tous les emplois associés à ces camions t ont une certaine date de ramassage,
  3. les employés affectés à ces emplois,
  4. et l'avance associée au travail.

Voici mon opération de recherche:

// app/models/truck.php 
$this->find('all', array(
    'contain' => array(
     'Job' => array(
      'Employee', 
      'Lead', 
      'conditions' => array(
       'Job.pickup_date' => $date 
      ) 
     ) 
    ) 
)); 

Pour une raison quelconque, gâteau fait la requête pour trouver des employés DEUX FOIS. Cela conduit à avoir tous les employés représentés deux fois pour chaque travail. Voici la décharge SQL:

  1. SELECT `Truck`.`id`, `Truck`.`truck_number` 
    FROM `trucks` AS `Truck` 
    WHERE 1 = 1;
  2. SELECT `Job`.`id`, `Job`.`lead_id`, `Job`.`city`, 
         `JobsTruck`.`id`, `JobsTruck`.`job_id`, `JobsTruck`.`truck_id` 
    FROM `jobs` AS `Job` 
    JOIN `jobs_trucks` AS `JobsTruck` ON (`JobsTruck`.`truck_id` IN (2, 3) 
    AND `JobsTruck`.`job_id` = `Job`.`id`) 
    WHERE `Job`.`pickup_date` = '2010-10-06'
  3. SELECT `Lead`.`id`, `Lead`.`name`, `Lead`.`created` FROM `leads` AS `Lead` 
    WHERE `Lead`.`id` = 4
  4. SELECT `Employee`.`id`, `Employee`.`name`, `Employee`.`created`, 
         `EmployeesJob`.`id`, `EmployeesJob`.`employee_id`, 
         `EmployeesJob`.`job_id` 
    FROM `employees` AS `Employee` 
    JOIN `employees_jobs` AS `EmployeesJob` 
         ON (
          `EmployeesJob`.`job_id` = 1 AND 
          `EmployeesJob`.`employee_id` = `Employee`.`id` 
         )
  5. SELECT `Lead`.`id`, `Lead`.`name`, `Lead`.`created` FROM `leads` AS `Lead` 
    WHERE `Lead`.`id` = 4
  6. SELECT `Employee`.`id`, `Employee`.`name`, `Employee`.`created`, 
         `EmployeesJob`.`id`, `EmployeesJob`.`employee_id`, 
         `EmployeesJob`.`job_id` 
    FROM `employees` AS `Employee` 
    JOIN `employees_jobs` AS `EmployeesJob` 
         ON (
          `EmployeesJob`.`job_id` = 1 AND 
          `EmployeesJob`.`employee_id` = `Employee`.`id` 
         )

Notez que les deux dernières requêtes sont des doublons. Ai-je fait quelque chose de mal que j'ai manqué?

MISE À JOUR
Il semble gâteau envoie une requête en double pour chaque camion. Maintenant que j'ai 15 enregistrements dans la table des camions, les requêtes à leads et employees sont dupliquées 15 fois chacune.

Répondre

3

Je ne sais pas pourquoi il y a deux requêtes dupliquées mais peut-être ce comportement peut vous aider:

https://github.com/Terr/linkable

MISE À JOUR

Ce genre de problème est bien connu:

+0

Cela semble intrigant. Je vais vérifier quand je vais travailler lundi. – Stephen

+0

Génial, Rio. Merci pour la découverte des faits. – Stephen

+0

Donc, ce billet a 2 ans. Apparemment, ils ciblent CakePHP 2.0 pour résoudre le problème. Pour l'instant je recourt à la division des requêtes en plusieurs appels à $ this-> find' et à la construction manuelle du tableau de données, ce qui est nul, mais ça craint beaucoup moins quand on passe de 80 requêtes à 4 requêtes. – Stephen

-3

Vous voulez LEFT JOIN au lieu de JOIN.Ne me demandez pas comment faire dans cakephp, je suis content que mon code fonctionne actuellement. ^^

+0

La question concerne CakePHP. Bonne journée Monsieur. – Stephen

+0

:: sigh :: Le jeu de résultats est * fine *. Changer le JOIN ne résoudra pas le problème. Le problème est que CakePHP lance les mêmes requêtes plusieurs fois. thaRRR11! à toi. – Stephen

+0

Tellement mauvais ....... – c0rnh0li0

1

Il n'y a rien pour rejoindre le Job/s trouvé à un Truck spécifique.

(J'espère que mon explication est pas trop difficile à comprendre, mais CakePHP peut être de cette façon parfois! IMHO)

Les Jobs sont attribuées à la Trucks d'une manière presque arbitraire (ma mémoire Le gâteau est que cela peut arriver); la nature de l'appel HABTM attache le Job/s à chacun des 15 Trucks. Cela semble être le processus actuel de mon point de vue;

  • Obtenez tous les camions.
  • Obtenez tous les emplois pour les camions où la date est x.
  • [Problème 1] Joignez le Jobs trouvé à chaque Truck (c'est-à-dire vos 15 camions), mais attaché à chaque Truck.
  • [Problème 2] Obtenez toutes les Leads/employés liés à ce Job, nouveau pour chaque Truck.

Problème 1: La source du problème. Vous pouvez voir dans la deuxième requête (SELECT Job ...), où il utilise le bon truck_id dans l'instruction ON, mais Cake ne peut pas "joindre" ces Jobs dans le droit Truck, parce que c'est une requête différente! Donc, il rejoint les emplois trouvés à chaque Truck.

Problème 2: Ce problème est le « réel », pour le gâteau ne construit pas longtemps REJOIGNEZ déclarations, donc il n'y a aucun moyen de trouver le Employees/Leads seulement pour ceux Trucks que vous voulez. C'est pourquoi il les trouve pour chaque camion, c'est parce que vous faites un FindAll sur Truck.

J'espère que cela a du sens. Vous devez faire une recherche tous sur Jobs, puisque c'est le 'center' de la requête (pickup_date).

$this->loadModel('Job'); 
$whatev = $this->Job->find('all', array(
    'contain' => array(
     'Job' => array(
      'Truck', 
      'Employee', 
      'Lead', 
      'conditions' => array(
       'Job.pickup_date' => $date 
      ) 
     ) 
    ) 
)); 

requêtes CakePHP vraiment ne fonctionnent que lorsque vous trouvez un/tous d'un certain modèle, il est préférable de commencer au milieu et travailler de chaque côté si vous avez une relation double HABTM. Si vous souhaitez «trier» par Truck, vous devrez peut-être écrire votre propre requête (méthode du modèle) pour accomplir la tâche vous-même. En SQL brut, cette requête peut être facile, dans PHP super-cake-ness abstraite c'est difficile à autoriser pour CakePHP.

Bonne cuisson, comme on dit!

+0

Cela semble prometteur, mais vouliez-vous contenir Job sur Job? – Stephen

+0

J'ai un secret. Il y a une autre relation: 'Truck -> hasMany -> TruckLog'. (Je l'ai laissé hors de l'exemple par souci de simplicité) En déplaçant la requête pour la centraliser autour de 'Job' au lieu de' Truck', je commence à avoir le même problème avec 'TruckLog' (les requêtes sont dupliquées pour chaque travail associé à un camion). – Stephen

+0

Vous avez raison sur le Job contenant Job, qui était un de mes oublis. Particulièrement avec la relation HABTM supplémentaire TruckLog, vous aurez certainement besoin de créer une méthode de modèle qui trouve exactement ce que vous voulez. Vous pouvez avoir besoin d'une requête SQL en utilisant $ Model-> query(), et probablement utiliser une sous-requête/s pour réaliser ceci en une requête (plus rapide pour la performance probablement). Vous pouvez également utiliser une méthode de modèle qui les trouve individuellement et utiliser la fusion de tableaux (http://book.cakephp.org/view/679/merge) pour traiter les résultats de chaque élément. – Ghostpsalm