Модель CakePHP использует неправильные поля в операторах SQL!

У меня есть куча моделей с различными ассоциациями, установленными между ними, и кажется, что Cakephp иногда выполняет неверный оператор SQL и вызывает рвоту MySQL.

Например, если у меня есть две модели, комментарий и тег и такой код:

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

дает оператор SQL:

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

Это происходит не постоянно, но в конце концов это происходит, потому что я делаю все по замкнутому кругу.

Пожалуйста помоги. Это действительно заставляет меня усомниться в моем решении пойти с Cake, так как это звучит плохо.

Спасибо.

EDIT 1 Я только что столкнулся с проблемой, и вот ошибочный SQL:

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

AlbumSong и ArtistGenre — это две совершенно разные таблицы, и они никак не связаны между собой.

EDIT 2 Только что столкнулся с очередной ошибкой. Код:

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

В то время как сгенерированный SQL:

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

Как вы можете видеть, в условиях я не указываю Artist.name, но сгенерированный SQL смотрит на него.

EDIT 3 Еще один пример ошибки. Вызов следующий:

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

Тем не менее, SQL:

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

где Artist.name не является столбцом Song, поскольку принадлежит модели Artist.

Спасибо.

ИЗМЕНИТЬ 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' => ''
                    )
            );
    }

    ?>

Вот и все. Для краткости я удалил код проверки.

Большое спасибо!


person TopQ    schedule 15.11.2010    source источник
comment
Определили ли вы условия по умолчанию в определениях ассоциации (belongsTo, HABTM или hasMany) для модели тегов или модели комментариев?   -  person yvoyer    schedule 15.11.2010
comment
Не могли бы вы показать нам определение ассоциаций ваших моделей и содержание метода, в котором вы вызываете.   -  person yvoyer    schedule 15.11.2010
comment
Не могли бы вы опубликовать вызов, который вы используете для создания sql.   -  person yvoyer    schedule 15.11.2010
comment
См. Редактировать 2. Спасибо.   -  person TopQ    schedule 16.11.2010
comment
Возможно, это связано с этим багом? cakephp.lighthouseapp.com/projects/42648/tickets/ Пожалуйста, предоставьте любую информацию, какую сможете.   -  person deceze♦    schedule 17.11.2010
comment
Я разместил ассоциацию моделей как Edit 4. Спасибо.   -  person TopQ    schedule 22.11.2010
comment
@deceze Моя проблема очень похожа на то, что было сообщено в этом билете! Я тоже выполнял это в оболочке...   -  person TopQ    schedule 22.11.2010


Ответы (5)


У меня была возможно такая же проблема. Проблема, с которой я столкнулся, заключалась в столкновении с кешем в реализации торта для кэширования условий (т. Е. Предложения WHERE) проанализированного sql.

Для торта 1.3 результаты DboSource::conditions() и DboSource::name() кэшируются по умолчанию. см.: DboSource. Кэш использует алгоритм хеширования crc32, который имеет более высокую вероятность коллизии. Кроме того, выполнение запросов в узком цикле также может увеличить вероятность коллизии. Это может объяснить, почему у вас есть несоответствующие имена таблиц в форме

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

Решение состояло в том, чтобы настроить источник данных так, чтобы это кэширование не выполнялось. Так что постарайтесь

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

перед использованием методов, генерирующих операторы sql.

person EricC    schedule 06.11.2013

Убедитесь, что у вас нет чего-то вроде этого:

class Tag extends AppModel
{
    public $belongsTo = array (
        'Comment' => array(
            'conditions' => array(
                'id' => 3, // Will add this condition on every query.
            ),
        )
    );
}
person yvoyer    schedule 15.11.2010
comment
Нет, у меня нет такого. Спасибо. - person TopQ; 15.11.2010

Не уверен, что эта ошибка как-то связана с тем, какую версию вы используете:

[eb76ab9] Исправлена ​​ошибка, из-за которой Model::saveAll() неправильно фиксировала транзакцию, которая не была запущена в самом вызове этой функции.

http://cakephp.org/changelogs/1.3.6

person woodscreative    schedule 16.11.2010

попробуйте вставить $this-ModelName->create() перед тем, как установить идентификатор и сохранить/найти. все, что нужно сделать, это очистить любые другие данные, которые висят вокруг. немного взломать, но если это работает, может дать некоторые подсказки к реальной проблеме.

person dogmatic69    schedule 22.11.2010

Я изучаю CakePHP последние несколько месяцев, и подобные вещи время от времени сводили меня с ума. Комментарий Dogmatic об использовании ->create() перед вашим вызовом может помочь, если вы использовали эту модель ранее в своей функции, он сбросит внутреннее состояние модели, чтобы устаревшие значения не мешали. Это может быть не ваша проблема.

Я согласен с yvover и bancer, что это, вероятно, вопрос взаимоотношений. Размещение ваших моделей (или ссылок на код) было бы большим подспорьем. Во время разработки я не раз ловил себя на том, что думал, что редактирую модель для класса, хотя на самом деле редактировал что-то еще из-за несоответствия имени, поэтому изменения не отражались, потому что моя «модель» никогда не загружалась.

person MBCook    schedule 22.11.2010
comment
Я вызываю model->create() перед всеми вызовами сохранения. Нужно ли мне делать это и для любых вызовов -›find()? - person TopQ; 22.11.2010
comment
Я разместил ассоциацию моделей как Edit 4. Спасибо. - person TopQ; 22.11.2010