2010-11-15 16 views
2

J'ai un tas de modèles avec diverses associations mises en place entre eux et semble que Cakephp exécute parfois une instruction SQL incorrecte et provoque MySQL à barf.CakePHP Model utilise les mauvais champs dans les instructions SQL!

Par exemple, si j'ai deux modèles, commenter et Tag et un code comme ceci:

$this->Comment->id = 5; 
$this->Comment->saveField('read_count', 3); 

donne instruction SQL:

UPDATE comments SET read_count = 3 WHERE Tag.id = 3; 

Il ne se produit pas tout le temps, mais il finalement arrive puisque je fais tout dans une boucle serrée.

Aidez-nous s'il vous plaît. Cela me fait vraiment douter de ma décision d'aller avec Cake car cela semble mauvais.

Merci.

EDIT 1 Je viens de rencontrer le problème et voici le SQL défectueux:

SELECT COUNT(*) AS `count` FROM `albums_songs` AS `AlbumSong` WHERE `ArtistGenre`.`id` = 26482 

AlbumSong et ArtistGenre sont deux tables complètement séparés et ils ne sont pas liés du tout.

EDIT 2 Juste couru dans un autre échec. Le code est:

$this->Song->find('first', array('conditions' => array('Song.artist_id' => 30188, 'Song.name' => 'Pal Pal (By.Tarkhanz)'), 'fields' => array('Song.id'))) 

Alors que le SQL généré est:

SELECT `Song`.`id` FROM `songs` AS `Song` WHERE `Artist`.`name` = 'Annie Villeneuve' LIMIT 1 

Comme vous pouvez le voir ne sont dans les conditions dois-je spécifier un Artist.name encore le SQL généré est à la recherche dans ce domaine.

EDIT 3 Un autre exemple d'échec. Appel est comme suit:

$this->Song->id = $song_id; 
$library_count = $this->Song->field('Song.library_count'); 

Pourtant, le SQL est:

SELECT `Song`.`library_count` FROM `songs` AS `Song` WHERE `Artist`.`name` = 'Mazikana_Ragheb_Allama' LIMIT 1 

où Artist.name est pas une colonne de la chanson comme il appartient au modèle de l'artiste.

Merci.

EDIT 4

models/album.php 

    <?php 
    class Album extends AppModel { 
      var $name = 'Album'; 
      var $belongsTo = array(
        'Artist' => array(
          'className' => 'Artist', 
          'foreignKey' => 'artist_id', 
          'conditions' => '', 
          'fields' => '', 
          'order' => '' 
        ) 
      ); 

      var $hasAndBelongsToMany = array(
        'Song' => array(
          'className' => 'Song', 
          'joinTable' => 'albums_songs', 
          'foreignKey' => 'album_id', 
          'associationForeignKey' => 'song_id', 
          'unique' => true, 
          'conditions' => '', 
          'fields' => '', 
          'order' => '', 
          'limit' => '', 
          'offset' => '', 
          'finderQuery' => '', 
          'deleteQuery' => '', 
          'insertQuery' => '' 
        ) 
      ); 

      var $hasMany = array(
        'AlbumSong' => array(
          'className' => 'AlbumSong', 
          'foreignKey' => 'album_id', 
          'dependent' => false, 
          'conditions' => '', 
          'fields' => '', 
          'order' => '', 
          'limit' => '', 
          'offset' => '', 
          'exclusive' => '', 
          'finderQuery' => '', 
          'counterQuery' => '' 
        ) 
      ); 
    } 

    ?> 

    models/album_song.php 

    <?php 
    class AlbumSong extends AppModel { 
      var $name = 'AlbumSong'; 
      var $useTable = 'albums_songs'; 
      var $belongsTo = array(
        'Song' => array(
          'className' => 'Song', 
          'foreignKey' => 'song_id', 
          'conditions' => '', 
          'fields' => '', 
          'order' => '' 
        ), 
        'Album' => array(
          'className' => 'Album', 
          'foreignKey' => 'album_id', 
          'conditions' => '', 
          'fields' => '', 
          'order' => '' 
        ) 
      ); 
    } 

    ?> 

    models/artist.php 
    <?php 
    class Artist extends AppModel { 
      var $name = 'Artist'; 
      var $hasMany = array(
        'Album' => array(
          'className' => 'Album', 
          'foreignKey' => 'artist_id', 
          'dependent' => false, 
          'conditions' => '', 
          'fields' => '', 
          'order' => '', 
          'limit' => '', 
          'offset' => '', 
          'exclusive' => '', 
          'finderQuery' => '', 
          'counterQuery' => '' 
        ), 
        'Song' => array(
          'className' => 'Song', 
          'foreignKey' => 'artist_id', 
          'dependent' => false, 
          'conditions' => '', 
          'fields' => '', 
          'order' => '', 
          'limit' => '', 
          'offset' => '', 
          'exclusive' => '', 
          'finderQuery' => '', 
          'counterQuery' => '' 
        ), 
        'ArtistGenre' => array(
          'className' => 'ArtistGenre', 
          'foreignKey' => 'artist_id', 
          'dependent' => false, 
          'conditions' => '', 
          'fields' => '', 
          'order' => '', 
          'limit' => '', 
          'offset' => '', 
          'exclusive' => '', 
          'finderQuery' => '', 
          'counterQuery' => '' 
        ) 
      ); 
    } 

    ?> 

    models/artist_genre.php 

    <?php 
    class ArtistGenre extends AppModel { 
      var $name = 'ArtistGenre'; 
      var $useTable = 'artists_genres'; 
      var $belongsTo = array(
        'Artist' => array(
          'className' => 'Artist', 
          'foreignKey' => 'artist_id', 
          'conditions' => '', 
          'fields' => '', 
          'order' => '' 
        ), 
        'Genre' => array(
          'className' => 'Genre', 
          'foreignKey' => 'genre_id', 
          'conditions' => '', 
          'fields' => '', 
          'order' => '' 
        ) 
      ); 
    } 

    ?> 

    models/genre.php 

    <?php 
    class Genre extends AppModel { 
      var $name = 'Genre'; 
      var $hasAndBelongsToMany = array(
        'Artist' => array(
          'className' => 'Artist', 
          'joinTable' => 'artists_genres', 
          'foreignKey' => 'genre_id', 
          'associationForeignKey' => 'artist_id', 
          'unique' => true, 
          'conditions' => '', 
          'fields' => '', 
          'order' => '', 
          'limit' => '', 
          'offset' => '', 
          'finderQuery' => '', 
          'deleteQuery' => '', 
          'insertQuery' => '' 
        ) 
      ); 

      var $hasMany = array(
        'ArtistGenre' => array(
          'className' => 'ArtistGenre', 
          'foreignKey' => 'genre_id', 
          'dependent' => false, 
          'conditions' => '', 
          'fields' => '', 
          'order' => '', 
          'limit' => '', 
          'offset' => '', 
          'exclusive' => '', 
          'finderQuery' => '', 
          'counterQuery' => '' 
        ) 
      ); 
    } 

    ?> 

    models/song.php 

    <?php 
    class Song extends AppModel { 
      var $name = 'Song'; 
      var $belongsTo = array(
        'Artist' => array(
          'className' => 'Artist', 
          'foreignKey' => 'artist_id', 
          'conditions' => '', 
          'fields' => '', 
          'order' => '' 
        ) 
      ); 
      /* 
      var $hasAndBelongsToMany = array(
        'Album' => array(
          'className' => 'Album', 
          'joinTable' => 'albums_songs', 
          'foreignKey' => 'song_id', 
          'associationForeignKey' => 'album_id', 
          'unique' => true, 
          'conditions' => '', 
          'fields' => '', 
          'order' => '', 
          'limit' => '', 
          'offset' => '', 
          'finderQuery' => '', 
          'deleteQuery' => '', 
          'insertQuery' => '' 
        ) 
      ); 
      */ 
      var $hasMany = array(
        'AlbumSong' => array(
          'className' => 'AlbumSong', 
          'foreignKey' => 'song_id', 
          'dependent' => false, 
          'conditions' => '', 
          'fields' => '', 
          'order' => '', 
          'limit' => '', 
          'offset' => '', 
          'exclusive' => '', 
          'finderQuery' => '', 
          'counterQuery' => '' 
        ) 
      ); 
    } 

    ?> 

C'est à peu près de celui-ci. Par soucis de brièveté, j'ai supprimé le code de validation .

Merci beaucoup!

+1

Avez-vous défini des conditions par défaut, dans les définitions d'association (belongsTo, HABTM ou hasMany), pour les balises modèle ou modèle de commentaires? – yvoyer

+0

Pourriez-vous nous montrer la définition de vos associations de modèles et le contenu de la méthode où vous vous appelez. – yvoyer

+0

S'il vous plaît voir Modifier 1. – TopQ

Répondre

0

Assurez-vous de ne pas avoir quelque chose comme ceci:

class Tag extends AppModel 
{ 
    public $belongsTo = array (
     'Comment' => array(
      'conditions' => array(
       'id' => 3, // Will add this condition on every query. 
      ), 
     ) 
    ); 
} 
+0

Non, je n'ai pas quelque chose comme ça. Merci. – TopQ

0

Je ne sais pas si ce bug n'a rien à voir avec elle, quelle version vous utilisez:

[eb76ab9] Correction du problème où Modèle: : saveAll() commettrait incorrectement une transaction qui n'a pas été démarrée dans cette fonction.

http://cakephp.org/changelogs/1.3.6

+0

Je suis sur Gâteau 1.3.4. Peut-être que je devrais mettre à jour à 1.3.6 ... – TopQ

+0

Mis à jour à 1.3.6 et toujours avoir un problème ... – TopQ

0

essayez de coller ce-ModelName- $> create() avant de configurer l'ID et enregistrer/trouver. Tout ce qui est clair, c'est toute autre donnée qui traîne. un peu un hack, mais si cela fonctionne pourrait fournir des indices sur le vrai problème.

0

J'ai appris CakePHP au cours des derniers mois et ce genre de chose m'a parfois rendu fou. Le commentaire de dogmatic à propos de l'utilisation de -> create() avant votre appel peut vous aider si vous avez utilisé ce modèle plus tôt dans votre fonction, il réinitialisera l'état interne du modèle afin que les valeurs périmées n'interfèrent pas. Ce n'est peut-être pas votre problème. Je suis d'accord avec yvover et bancer sur le fait qu'il s'agit probablement d'un problème de relations. Poster vos modèles (ou des liens vers le code) serait d'une grande aide. La chose qui m'a le plus interpellé au cours du développement était de penser que je modifiais le modèle pour une classe alors que je modifiais autre chose en raison d'une différence de nom, donc les changements n'étaient pas reflétés car mon «modèle» n'était jamais chargé.

+0

J'appelle model-> create() avant tous les appels de sauvegarde. Ai-je besoin de faire ça pour tout -> find() aussi? – TopQ

+0

J'ai publié l'association de modèles en tant que Modifier 4. Merci. – TopQ

1

J'ai probablement eu le même problème. Le problème que j'ai rencontré était la collision de cache dans l'implémentation de la mise en cache des conditions (c'est-à-dire la clause WHERE) d'un sql analysé.

Pour le gâteau 1.3, les résultats de DboSource::conditions() et DboSource::name() sont mis en cache par défaut. voir: DboSource. Le cache utilise l'algorithme de hachage crc32, qui a un plus grand risque de collision. En outre, exécuter des requêtes dans une boucle serrée peut également augmenter le risque de collision. Cela peut expliquer pourquoi vous avez des noms de table désadaptation sous forme de

select * from `table_A` where `table_B`.`field` ... 

La solution était de définir la source de données pour ne pas faire la mise en cache. Donc, essayez

$ds = $this->Comment->getDataSource(); 
$ds->cacheMethods = false; 

avant d'utiliser les méthodes qui génèrent des instructions sql.