CakePHP не извлекает строки на определенное число для связи hasOne

#php #mysql #cakephp #relational-database #cakephp-model

#php #mysql #cakephp #реляционная база данных #cakephp-модель

Вопрос:

У меня есть клиент с базой данных, которая содержит несколько масштабируемых и взаимосвязанных моделей. Мы столкнулись со странной «ошибкой» в создаваемом нами отношении $ hasOne. Проблема в этом:

Модель UsersItems имеет отношение $ hasOne с пользователями. Это заключается в следующем

 var $hasOne = array(
    'Author' => array(
        'className' => 'User',
        'foreignKey' => 'id'
    )
);
  

Это извлекает и объединяет пользовательские данные с псевдонимом «Author» для этих элементов (которые также принадлежат пользователям в контексте пользователей, которые выбрали их для «закладки»).

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

Однако, если пользовательский элемент имеет, скажем, id значение 5000 (верхний диапазон текущего размера таблицы), этот $ hasOne не может извлечь какую-либо информацию из find() . Следовательно, казалось бы, более новые элементы с «закладками» не извлекают данные автора, в то время как другие («более старые») работают просто отлично.

Что могло бы быть причиной этого?

ДОБАВЛЕНА ИНФОРМАЦИЯ

Запрос выглядит следующим образом:

 SELECT `UsersItem`.`id`, `UsersItem`.`user_id`, `UsersItem`.`item_id`,
       `UsersItem`.`in_list`, `User`.`id`, `User`.`username`, `User`.`password`,
       `User`.`email`, `User`.`group_id`, `User`.`resethash`, `User`.`confirmhash`,
       `User`.`confirmed`, `Item`.`id`, `Item`.`user_id`, `Item`.`name`,
       `Item`.`category_id`, `Item`.`description`, `Item`.`pagelink`,
       `Item`.`purchaselink`, `Item`.`moderated`, `Item`.`image_filename`,
       `Item`.`votecount`, `Item`.`parent_id`, `Item`.`discover_order`,
       `Item`.`created`, `Item`.`slug`, `Item`.`normalized_name`,
       ((`Item`.`votecount`)/pow((3600*TIMEDIFF(`Item`.`created`, NOW())   12), .42)) AS `Item__rank`,
       `Author`.`id`, `Author`.`username`, `Author`.`password`, `Author`.`email`,
       `Author`.`group_id`, `Author`.`resethash`, `Author`.`confirmhash`,
       `Author`.`confirmed`
FROM `users_items` AS `UsersItem`
LEFT JOIN `users` AS `User` ON (`UsersItem`.`user_id` = `User`.`id`)
LEFT JOIN `items` AS `Item` ON (`UsersItem`.`item_id` = `Item`.`id`)
LEFT JOIN `users` AS `Author` ON (`Author`.`id` = `UsersItem`.`id`)
WHERE `UsersItem`.`user_id` = 1118
  AND `UsersItem`.`in_list` = 1
ORDER BY `UsersItem`.`id` DESC
  

ВТОРОЕ ДОПОЛНЕНИЕ

Этот запрос действительно работает:

 SELECT `UsersItem`.`id`, `UsersItem`.`user_id`, `UsersItem`.`item_id`, `UsersItem`.`in_list`, `User`.`id`, `User`.`username`, `User`.`password`, `User`.`email`, `User`.`group_id`, `User`.`resethash`, `User`.`confirmhash`, `User`.`confirmed`, `Item`.`id`, `Item`.`user_id`, `Item`.`name`, `Item`.`category_id`, `Item`.`description`, `Item`.`pagelink`, `Item`.`purchaselink`, `Item`.`moderated`, `Item`.`image_filename`, `Item`.`yeekcount`, `Item`.`parent_id`, `Item`.`discover_order`, `Item`.`created`, `Item`.`slug`, `Item`.`normalized_name`, ((`Item`.`yeekcount`)/pow((3600*TIMEDIFF(`Item`.`created`, NOW())   12), .42)) AS `Item__rank`, `Author`.`id`, `Author`.`username`, `Author`.`password`, `Author`.`email`, `Author`.`group_id`, `Author`.`resethash`, `Author`.`confirmhash`, `Author`.`confirmed` FROM `users_items` AS `UsersItem` LEFT JOIN `users` AS `User` ON (`UsersItem`.`user_id` = `User`.`id`) LEFT JOIN `items` AS `Item` ON (`UsersItem`.`item_id` = `Item`.`id`) LEFT JOIN `users` AS `Author` ON (`Author`.`id` = `Item`.`user_id`) WHERE `UsersItem`.`user_id` = 1118 AND `UsersItem`.`in_list` = 1 ORDER BY `UsersItem`.`id` DESC
  

Обратите внимание на разницу в этом конкретном бите:

 LEFT JOIN `users` AS `Author` ON (`Author`.`id` = `Item`.`user_id`)
  

Ранее я извлекал неправильное значение id в качестве идентификатора автора, поэтому я знаю, что в этом была проблема; теперь я пытаюсь выяснить, как заставить Cake сгенерировать этот правильный запрос…

Комментарии:

1. Что такое сгенерированные SQL-запросы, как происходит сбой?

2. Я обновлю их как можно скорее.

3. Добавлена новая информация к исходному вопросу.

4. Работает ли этот запрос, если вы выполняете его вручную в базе данных? Есть ли запись, в users которой совпадают UsersItem.id ?

5. Запрос работает не лучше, если выполняется вручную в базе данных. Те же самые элементы возвращаются с недостающей информацией, относящейся к Автору. В настоящее время не существует соответствующей записи в Users, которая соответствовала бы UsersItem.id. Мне кажется, я вижу, к чему ведет ответ…

Ответ №1:

Возможно, вам следует переключить отношение Author на belongsTo вместо hasOne в вашей модели элементов следующим образом :

 var $BelongsTo= array(
'Author' = array(
    'className' => 'User',
    'foreignKey' => 'user_id');
  

в книге это очень хорошо объясняется, внешний ключ в отношении belongsTo — это то, что вам нужно :

ForeignKey: имя внешнего ключа, найденного в текущей модели. Это особенно удобно, если вам нужно определить несколько отношений belongsTo. Значением по умолчанию для этого ключа является подчеркнутое имя другой модели в единственном числе с суффиксом ‘_id’.

Надеюсь, я помог 🙂 .

Ответ №2:

Если я правильно понял ваш запрос, ваша ассоциация должна была быть такой:

В модели пользовательского элемента:

 var $belongsTo= array(
    'User', 'Item'
);
  

В модели элемента:

 var $hasMany = array(
    'UserItem'
);

var $hasOne = array(
    'Author' = array(
        'className' => 'User',
        'foreignKey' => 'id'
);
  

Я надеюсь, что это поможет.

Комментарии:

1. Как вы запрашиваете свою модель? используя сдерживаемое поведение? можем ли мы получить выполняемый вами запрос find?

2. это не тестировалось. я просто напечатал это, думая об этом.

Ответ №3:

Ни один из ответов здесь не сработал для меня. К лучшему или к худшему, в итоге я создал виртуальное поле, которое заполняло бы значение имени автора.

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

Виртуальные таблицы вызываются в каждом экземпляре внешнего вида этой модели. Это означает, что даже в связи UsersItems-> Items элементы будут заполнять его виртуальные поля.

То, что я в итоге создал в item.php файл модели выглядел примерно так:

 var $virtualFields = array(
    'author' => 'SELECT `username` FROM `users` WHERE `id = Item.user_id`'
);
  

Я буду ждать ответа от других относительно того, является ли это подходящим решением этой проблемы, но пока это единственное, которое сработало для меня. Поскольку в таблице UsersItems нет связанного author_id столбца, я просто не понимаю, как можно было бы связать эти две таблицы.

Комментарии:

1. Я думаю, вы искали что — то вроде этого — bakery.cakephp.org/articles/eldonbite/2008/09/18 /…

2. Возможно. Я могу вернуться к этому подходу подкласса.

Ответ №4:

Я предполагаю, что в какой-то момент идентификаторы Author и UserItem не синхронизированы, т. Е. Идентификатор автора 3445 имеет один идентификатор UserItem 3445, но идентификатор автора 5000 имеет один идентификатор UserItem 5001 или что-то в этом роде, и запрос пытается получить идентификатор неправильной таблицы. Но, не видя сгенерированных запросов, трудно сказать.