2010-02-22 3 views
11

Ich habe eine CakePHP 1.3 App und genieße wirklich die Containable behavior zum Abrufen von Daten.CakePHP Model: COUNT (*) in Containable

Nehmen wir an, ich habe Beiträge in einer Eins-zu-viele-Beziehung mit Kommentaren. Ich benutze Containable, um eine Liste aller Posts und der zugehörigen Kommentare abzufragen. Aber ich bin nur daran interessiert, wie viele Kommentare jeder Beitrag hat. Ich habe keine Möglichkeit gefunden, diese Abfrage mit containable zu erreichen, ohne alle Zeilen von Kommentaren zu holen. Ich habe versucht:

Ergebnisse in 'Model "Kommentar" ist nicht mit Modell "Count"' Fehlermeldung verbunden.

$this->paginate=array(
      'fields' => array('Post.title, Post.created'), 
      'contain' => array('Comment'=>array('fields'=>'COUNT(*) AS count'), 
     ); 

nicht funktioniert, Ergebnismenge für jeden Beitrag einen leeren Kommentar Array enthält mit Ausnahme der letzten, wo es das Zählfeld enthält, aber die Anzahl aller Kommentare nicht nur die Zugehörigkeit solche mit.

Meine andere Vermutung war

$this->paginate=array(
      'fields' => 'Post.title, Post.created, COUNT(Comment.id)', 
      'contain' => array('Comment'=>array('fields'=>''), 
     ); 

aber dies führt zu einem Fehler, weil hasMany Beziehungen unabhängig abgefragt werden, so dass die Antwort-Tabelle nicht in der Abfrage für die Post-Einträge ist. Wie kann ich die Anzahl der Kommentare zählen, die ein Beitrag hat?

Antwort

11

Nun, der beste Weg, dies zu tun, ist ein Feld comment_count in der posts Tabelle und fügen Sie diesen Schlüssel zum Kommentieren Modell $ belongsTo Beitrag Array genannt einzurichten:

'counterCache' => true

Jedes Mal, alles wird Bei den Kommentaren wird das Feld comment_count im zugehörigen Post aktualisiert (es wird jedes Mal neu gezählt, anstatt nur hinzuzufügen oder zu löschen).

Es ist besser, denn wenn Sie Daten für den Benutzer holen, ist es schneller und berührt nicht einmal die Kommentartabelle. Da Sie das Containable-Verhalten verwenden, denke ich, dass Geschwindigkeit und geringes Gewicht das sind, wonach Sie suchen.

+3

Das ist eine nette Idee, aber es löst nicht das Problem für komplexere Abfragen, bei denen das Halten einer mit einer Zeile verknüpften Zählung nicht funktionieren würde (zum Beispiel ein Berichtssystem, wo bestimmte Bedingungen vom Benutzer gewählt werden). Gibt es keinen anderen Weg, eine Zählung mit containable zu erhalten? – Zxaos

6

Ich hatte die gleiche Frage. Die Antwort, die PawelMysior gab, war großartig und führte zur Lösung.

Ich fand einige weitere Details in der CakePHP Buch: 3.7.4.1.1 counterCache - Cache your count(). Dies war hilfreich, aber immer noch ein bisschen vage. Um der anderen willen möchte ich einige weitere Einzelheiten angeben.

Ich habe zwei Tabellen: Post und Image. Wenn ich einem Beitrag ein Bild hinzugefügt habe, möchte ich wissen, wie viele Bilder jeder Beitrag zur Anzeige in der Post-Indexliste hatte, ohne dass eine zusätzliche Zählabfrage in der Image-Tabelle ausgeführt werden muss.

CREATE TABLE posts 
(
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, 
user_id INTEGER UNSIGNED NOT NULL, 
title VARCHAR(255), 
body TEXT, 
created DATETIME, 
modified DATETIME, 
image_count INTEGER UNSIGNED, 
PRIMARY KEY (id) 
) ENGINE=InnoDB; 

CREATE TABLE images 
(
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, 
post_id INTEGER UNSIGNED NOT NULL, 
filename VARCHAR(255), 
created DATETIME, 
modified DATETIME, 
PRIMARY KEY (id) 
) ENGINE=InnoDB; 

Beachten Sie, dass die image_count in der posts Tabelle geht. In der Tabelle images ist nichts besonderes erforderlich.

class Post extends AppModel 
{ 
    var $name = 'Memory'; 
    var $hasMany = array(
     'Image' => array(
      'className' => 'Image', 
      'foreignKey' => 'post_id', 
      'dependent' => false 
     ) 
    ); 
} 

class Image extends AppModel 
{ 
    var $name = 'Image'; 
    var $belongsTo = array(
     'Post' => array(
      'className' => 'Post', 
      'foreignKey' => 'post_id', 
      'counterCache' => true 
     ) 
    ); 
} 

Beachten Sie, dass counterCache zum Image Modell hinzugefügt wird. Nichts Besonderes wird in dem Modell Post benötigt.

$this->Post->Behaviors->attach('Containable'); 
$post = $this->Post->find('all', array(
    'conditions' => array('user_id' => 7), 
    'order' => array('Post.created DESC'), 
    'contain' => array(
     'Post' => array(
      'User' => array('first_name', 'last_name') 
     ) 
    ) 
)); 

Nun, wenn wir einen find es tun, ist keine Notwendigkeit, etwas zu tun besonderen die Zählung zu finden, weil es automatisch ein Feld in den Post Ergebnisse ist. Beachten Sie die image_count unten.

Array 
(
[Post] => Array 
     (
      [0] => Array 
       (
        [id] => 14 
        [user_id] => 7 
        [title] => Another great post 
        [body] => Lorem ipsum... 
        [created] => 2011-10-26 11:45:05 
        [modified] => 2011-10-26 11:45:05 
        [image_count] => 21 
        [User] => Array 
        (
         [first_name] => John 
         [last_name] => Doe 
        ) 
       ) 
     ) 
) 

Eine Sache zu beachten, wenn Sie counterCache zu einer bestehenden Datenbankstruktur hinzufügen, werden die Zählungen in Post Null sein, bis ein anderer Image hinzugefügt wird. An diesem Punkt führt CakePHP eine tatsächliche Zählung durch und aktualisiert die image_count auf den korrekten Wert.

Ich hoffe, dass diese zusätzlichen Informationen für jemanden hilfreich sind.