2012-10-24 15 views
5

Ho tre modelli, Utenti, Commenti e Pagine.Come posso ridurre al minimo le query 'contain' in CakePHP?

Utentiha moltiCommenti e CommentiappartengonoPagine.

Tutti i modelli utilizzano il comportamento containable e il valore predefinito è recursive -1.

Se io chiamo una query find() su Commenti, con il contiene richiesta, tra cui il campo Pagina modello, questo restituisce correttamente i risultati utilizzando una singola query, automagicamente adesione Pagina tavolo per l'utente.

Se io chiamo una query simile al modello utente (contenentecommento e Comment.Page), il risultato è una query di procurarsi i Commenti, seguita da una query per ogni commento a fonte la corrispondente Pagina.

C'è un modo per configurare i modelli per mantenere l'ottimizzazione JOIN? Ho assunto che la dichiarazione belongsTo sul modello correlato (Comments) seguisse il modello host (Users).

UPDATE

vorrei chiarire, la mia domanda utilizzato una versione semplificata del mio studio vero e proprio caso. Anche se la soluzione minima ho bisogno includerebbe questo iniziale ModellohasManyModellobelongsToModello struttura, sto anche cercando la soluzione ad uno o più ulteriori belongsTomodelle lungo la catena (che , Però, avrei usato automaticamente LEFT JOINs, perché sarebbe fattibile).

risposta

1

Quindi stai chiedendo se c'è un modo più semplice per contenere solo tutte le tue domande? Se si desidera contenere tutto all'interno del controller corrente. Si potrebbe fare il conteggio nel callback beforeFilter() e si applicherebbe a tutte le query all'interno di quel controller.

+1

Hi Colby. Ne hai un esempio in pratica? Credo che questo approccio possa essere d'aiuto con uno dei miei progetti e con i poster originali. –

+0

Credo che qualcosa del genere nel controller contenga le query per l'intero controller. 'function beforeFilter() \t { \t \t parent :: beforeFilter(); \t \t $ this-> Model-> contain ('RelatedModelStuff'); \t \t \t} // beforeFilter' –

+0

Grazie a Colby, questo non è esattamente quello che cercavo, ma la dichiarazione del filtro beforeFilter è uno snippet utile, applausi. – Rhys

1

Non sono sicuro di aver compreso la tua domanda, ma penso che tu abbia un problema con le numerose chiamate sql per il commento -> Linkage della pagina?Se questo è corretto, quindi

  1. provare linkable behaviour che riduce le chiamate SQL e funziona quasi come contiene Non
  2. o se la sua più o meno gli stessi dati che si desidera, quindi creare una funzione in un modello specifico da dove sei felice con chiamate HTE SQL (ad esempio il commento del modello) e chiamarlo dal modello utente $this->Comment->myFindFct($params);

speranza che aiuta

EDIT: una cosa che mi viene in mente. Sei stato in grado di modificare il tipo di join nell'array di associazione su inner, che ha reso la torta a chiamata singola anche il modello associato

2

Hmm è interessante. Questo è una sorta di ottimizzazione che dovrebbe essere attuato nel nucleo :)

In ogni caso, penso che si potrebbe ottenere gli stessi risultati (forse formattati in modo diverso) con la costruzione di query un po 'diverso:

$this->User->Comment->find('all', array(
    'conditions' => array(
    'Comment.user_id' => $userId 
), 
    'contain' => array(
    'User', 
    'Page' 
) 
)); 

Effettuando una ricerca dal modello Comment, è necessario utilizzare due join di sinistra per unire i dati poiché sono entrambe le relazioni 1: 1. Nota: la matrice dei risultati potrebbe apparire leggermente diversa rispetto a quando si esegue la ricerca dal modello Utente.

+0

Grazie jeremyharris. Questo avrebbe funzionato, ma dovevo chiarire la mia domanda sopra per mostrare che il caso reale richiede più livelli di connessioni. Lo terrò a mente come una possibilità, anche se se dovessi compilare manualmente le mie query, ciò farà risparmiare un po 'di tempo. – Rhys

1

Trovo che un buon modo per fare ciò è creare un custom find method.

Come per esempio, creo un metodo all'interno del modello utente, detto _findUserComments(). Dovresti quindi fare tutti i join, i contenuti, ecc. All'interno di questo metodo. Poi, nel vostro controller, ovunque è necessario per ottenere tutti i commenti del vostro utente si potrebbe chiamare così:

$this->User->find('UserComments', array(
    "conditions" => array(
     'User.id' => $userId 
    ) 
)); 

Spero che questo aiuta.

+0

Grazie Rob. Uso i metodi di ricerca personalizzati abbastanza estesamente, sono utili, ma ciò non aggirerebbe comunque la situazione della creazione di versioni estremamente manuali della query (join, ecc.) Per ottenere quello che avrei capito sarebbe stato ottimizzato automaticamente dal core. – Rhys

1

Se definizione modello come muggito:

  1. modello Commento appartiene alla pagina e utente.
  2. Pagina appartiene all'utente e ha molti commenti.
  3. utente ha molti pagina e commentare

codice muggito restituirà una uniti query:

$this->loadModel('Comment'); 
$this->Comment->Behaviors->attach('Containable'); 
$queryResult = $this->Comment->find('all', array(
    'contain' => array(
     'User', 
     'Page' 
    ) 
)); 

Il soffietto codice restituirà due query. Pagina e utente uniti in una query e tutti commento in un'altra query

$this->loadModel('Page'); 
$this->Page->Behaviors->attach('Containable'); 
$queryResult = $this->Page->find('all', array(
    'contain' => array(
     'User', 
    'Comment' 
    ) 
)); 

e anche il codice soffietto torneranno tre di query, uno per ogni modello:

$this->loadModel('User'); 
$this->User->Behaviors->attach('Containable'); 
$queryResult = $this->User->find('all', array(
    'contain' => array(
     'Page', 
     'Comment' 
    ) 
)); 
+0

Grazie, anche se la preoccupazione che nutro è per una struttura del modello che ha più collegamenti di proprietà verso la catena, piuttosto che un modello che appartiene a due modelli diversi. Per esempio. Restituzione di una singola query in cui Model1 appartiene a Model2, Model2 appartiene a Model3 e Model3 appartiene a Model4. I dati possono essere restituiti in una singola query utilizzando una dichiarazione personalizzata, ma la mia comprensione è che il core dovrebbe comunque gestire questa ottimizzazione. – Rhys

+0

Mi dispiace se non capisco la tua affermazione qui. Ma sulla tua domanda "Gli utenti hanno molti commenti e i commenti appartengono a Pages" equivalgono alla definizione del mio modello di cui sopra (vedi punti 3 e 1). E il risultato della query se la chiamata dal modello Utente è stata ottimizzata, basta restituire tre query (non ripetutamente interrogare la pagina per commento). – Habibillah

+0

Scusate, penso che il mio _update_ abbia chiarito il caso di studio più approfondito (degli appartameni concatenati) quando ho capito che la soluzione del caso di studio originale sarebbe risolvibile senza in realtà coprire il contesto della mia domanda – Rhys

Problemi correlati