Странное поведение доктрины с двойным innerJoin () - PullRequest
0 голосов
/ 24 октября 2010

У меня есть схема базы данных, подобная этой: Моя схема базы данных: http://i.stack.imgur.com/vFKRk.png

Чтобы объяснить контекст: один пользователь пишет одно сообщение. Он может отправить его одному или нескольким пользователям.

Мне удалось получить заголовок сообщения, автора для одного пользователя. Однако Doctrine, которую я использую для этого проекта, делает это с 2-мя запросами. Это немного странно для меня, и я пытаюсь понять, почему. Обычно мы можем сделать это одним SQL-запросом.

Мой DQL-запрос:

$q = Doctrine_Query::create()->select('id_me, users_id_us, state_me, type_me, mc.title_mc, us.login_us') ->from('messages m')->innerJoin('m.messages_content mc')->innerJoin('mc.Users us') ->where('users_id_us = ?', $user)->limit($opt['limit'])->offset($opt['offset'])->orderBy($opt['order']);return $q->fetchArray();

SQL-запросы, возвращаемые Doctrine:

SELECT DISTINCT m3.id_me FROM messages m3  INNER JOIN messages_content m4 ON m3.messages_content_id_mc = m4.id_mc  INNER JOIN users u2 ON m4.users_id_us = u2.id_us WHERE m3.users_id_us = '6' ORDER BY m3.id_me DESC LIMIT 2

SELECT m.id_me AS m__id_me, m.users_id_us AS m__users_id_us, m.state_me AS m__state_me, m.type_me AS m__type_me, m2.id_mc AS m2__id_mc, m2.title_mc AS m2__title_mc, u.id_us AS u__id_us, u.login_us AS u__login_us FROM messages m INNER JOIN messages_content m2 ON m.messages_content_id_mc = m2.id_mc INNER JOIN users u ON m2.users_id_us = u.id_us WHERE m.id_me IN ('11') AND (m.users_id_us = '6') ORDER BY m.id_me DESC

Почему мой запрос Doctrine не возвращает такой запрос:

SELECT m.id_me, m.users_id_us, m.state_me, m.type_me, mc.title_mc, u.login_us FROM messages m JOIN messages_content mc ON mc.id_mc = m.messages_content_id_mc JOIN users u ON u.id_us = mc.users_id_us WHERE m.users_id_us = 6;

Есть идеи преобразовать мой DQL-запрос и выполнить его один раз?

Ответы [ 3 ]

2 голосов
/ 25 октября 2010

Проблема с лимитом ORM

Это связано с частью LIMIT.:) Doctrine LIMIT работает немного иначе, чем MySQL limit.

MySQL LIMIT просто выдает запрос и прекращает поиск, как только найдено n строк, соответствующих вашему SQL-запросу.Так как в ORM это действительно неожиданное поведение (вполне может быть, что в скалярном макете SQL SELECT * FROM myModel LEFT JOIN someOtherModel ON someCondition LIMIT 3 фактически возвращает только один myModel экземпляр, а не три, так как левое соединение может привести к 3 строкам.

Что делает Doctrine?

Если ваш DQL-запрос FROM school s INNER JOIN s.students LIMIT 15, это означает: дайте мне 15 экземпляров school, у которых есть хотя бы один student (следовательно, INNER JOIN), с ALLиз их student партнеров. Для этого сначала Doctrine запрашивает DISTINCT school с точно такими же параметрами запроса и частью LIMIT, чтобы выяснить, какие 15 школьных идентификаторов должны быть возвращены. После этого эти идентификаторызапрашивается следующий, без части LIMIT.

Как решить вашу проблему

Если у вас нет реальной проблемы, huzzah, найдите объяснение этого поведения выше. Если ваш запрос вывода другойчем вы ожидали, убедитесь, что вы приняли эти шаги во внимание. Если, например, у вас DQL FROM school s INNER JOIN s.students LIMIT 15, и вам интересно, почему у вас более 15 студентов, попробуйте: FROM students s INNER JOIN s.school LIMIT 15. В MySQL tего значения в основном одинаковы (независимо от порядка результата), хотя в Doctrine это означает, что вы получите 15 students вместо 15 schools.

0 голосов
/ 31 октября 2010

Решение, которое работает:

Я изменил псевдоним отношения и указал столбцы, участвующие в объединении ON, между messages_content и пользователями.

Правильный запрос Doctrine:

$q = Doctrine_Query::create()
->select('id_me, users_id_us, state_me, type_me, mc.title_mc, us.login_us') 
->from('messages m')
->innerJoin('m.messages_content mc')
->innerJoin('m.Users us ON mc.users_id_us=us.id_us')    
->where('users_id_us = ?', $user)
->limit($opt['limit'])
->offset($opt['offset'])
->orderBy($opt['order']);

Выдает SQL-запрос, подобный следующему:

SELECT m.id_me AS m__id_me, m.users_id_us AS m__users_id_us, m.state_me AS m__state_me, m.type_me AS m__type_me, m2.id_mc AS m2__id_mc, m2.title_mc AS m2__title_mc, u.id_us AS u__id_us, u.login_us AS u__login_us FROM messages m INNER JOIN messages_content m2 ON m.messages_content_id_mc = m2.id_mc INNER JOIN users u ON (m2.users_id_us = u.id_us) WHERE (m.users_id_us = '7') ORDER BY m.id_me DESC LIMIT 2

Том и Пелле тен Кейт, спасибо за ваше участие.

0 голосов
/ 25 октября 2010

Меня это тоже беспокоило по поводу некоторых более сложных запросов. Единственное решение, которое я нашел, это вообще обойти глупость:

$q = Doctrine_Manager::getInstance()->getCurrentConnection();
$my_result = $q->fetchAssoc(" ... PUT SQL HERE ... ");
...