双内连接的奇怪主义行为()

时间:2010-10-24 17:18:46

标签: php orm doctrine

我有这样的数据库架构: 我的数据库架构: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();

Doctrine返回的SQL查询:

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 个答案:

答案 0 :(得分:2)

ORM限制问题

这与LIMIT部分有关。 :) Doctrine LIMIT与MySQL限制有点不同。

MySQL LIMIT只发出查询,并在找到与您的SQL查询匹配的n行后立即停止搜索。因为在ORM中,这实际上是意外的行为(很可能在标量布局中,SQL SELECT * FROM myModel LEFT JOIN someOtherModel ON someCondition LIMIT 3实际上只返回一个myModel实例而不是三个,因为左连接可以产生3行。 / p>

Doctrine做什么?

如果你的DQL查询是FROM school s INNER JOIN s.students LIMIT 15,则意味着:给我15个school个实例,这些实例至少有一个student关联(因此INNER JOIN),所有他们的student员工。为此,Doctrine首先要求DISTINCT school使用完全相同的查询参数和LIMIT部分,以确定应返回哪15个学校ID。完成此操作后,接下来将查询这些ID,而不使用LIMIT部分。

如何解决您的问题

如果你没有遇到实际问题,huzzah,请找到上述这种行为的解释。如果您的查询输出不是您预期的,请确保将这些步骤纳入考虑范围。例如,如果您的DQL为FROM school s INNER JOIN s.students LIMIT 15,并且您想知道为什么您的学生人数超过15人,请尝试:FROM students s INNER JOIN s.school LIMIT 15。在MySQL中,这意味着基本相同(忽略结果的顺序),但在Doctrine中,这意味着您将获得15 students而不是15 schools

答案 1 :(得分:0)

这也困扰了我一些更复杂的查询。我发现的唯一解决方案是完全绕过愚蠢行为:

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

答案 2 :(得分:0)

有效的解决方案:

我更改了关系别名,并指定了messages_content和users之间参与ON联合的列。

正确的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
汤姆和佩尔十个凯特,谢谢你的参与。