使用连接和偏移量时,Doctrine会跳过数据集

| 我正在使用PHP5.3上的Symfony 1.4中的Doctrine 1.2。 我有一个数据库,其中的事件具有多个开始日期时间(1:n)和类型(n:m)。 对于一个程序,我想要一个开始时间和事件标题的列表,它们属于一种特殊类型,并且不会过时:
$dql = Doctrine_Query::create()
  ->select(\'ed.start_datetime,e.title\')/*edd.*,*/
  ->from(\'EventDate ed\')
  ->leftJoin(\'ed.Event e\')
  ->leftJoin(\'e.EventTypes et\')
  ->leftJoin(\'e.Domain d\')
  ->orderBy(\'ed.start_datetime, ed.event_id\');
  ->where(\'e.start_datetime >= ? AND e3.id = ?\',array(\'2011-05-27 17:19:41\',2))
  ->fetchArray();
可以在pastebin.com/SdjvsaxW上查看该架构。 现在,学说有两个说法
SELECT DISTINCT e5.event_id FROM event_date e5 LEFT JOIN event e6 ON e5.event_id = e6.id LEFT JOIN event_event_type e8 ON (e6.id = e8.event_id) LEFT JOIN event_type e7 ON e7.id = e8.event_type_id WHERE (e5.start_datetime >= \'2011-05-27 17:19:41\' AND e7.id = \'2\') ORDER BY e5.start_datetime, e5.event_id

SELECT e.event_id AS e__event_id, e.start_datetime AS e__start_datetime, e2.id AS e2__id, e2.title AS e2__title FROM event_date e LEFT JOIN event e2 ON e.event_id = e2.id LEFT JOIN event_event_type e4 ON (e2.id = e4.event_id) LEFT JOIN event_type e3 ON e3.id = e4.event_type_id WHERE e.event_id IN (*all the IDs from the first query*) AND (e.start_datetime >= \'2011-05-27 17:19:41\' AND e3.id = \'2\') ORDER BY e.start_datetime, e.event_id
当我引入分页时,问题就开始了:当我添加一个偏移量时,它将被添加到第一个查询中。现在,由于一个事件的开始时间可能不止一个,因此来自第一个SELECT DISTINCT查询的ID的数量可能小于日期的数量。因此,日期可能会被跳过。就我而言,事件少于50个,因此尽管有数百个事件日期(由于重复发生的事件),但显示事件日期51-100的第二页确实是空的。 我认为可以解决这个问题,而不必担心有什么不同之处,但我无法控制。 有人知道吗?     
已邀请:
        当您具有基表并通过一对多关系进行联接时,Doctrine会以称为“限制子查询”的模式运行两个查询,第一个查询是不同的查询。这是因为您将选择联接的乘积,并且最终将得到比基表中的记录多的行。例如,如果事件#5有两个EventType,则数据库将在两行中返回事件#5。这两个查询行为仅在MySQL中有效,其他数据库可以在子查询中运行限制,并且Doctrine生成单个查询。 由于您的事件具有多个日期,并且EventDate具有复合主键,Doctrine应该在第一个查询中选择一组不同的(event_id,start_datetime),但是它似乎忽略了复合主键的第二部分,可能是因为无法将它们塞入第二个查询的ON子句中。 您可能可以通过以下两种或三种方式之一解决此问题: 1)向EventDate(自动增量列)添加唯一的主键。您可能不必在其他任何地方引用它,但是教义将开始使用 2)手动执行2个查询。从EventDate中选择所有不同的event_id,start_datetime,添加限制和偏移量,然后以编程方式创建where子句:
 ... WHERE ((event_id = ? AND start_datetime = ?) OR (event_id = ? AND start_datetime = ?))... 
3)重新排序查询以从其他表开始或在选择中添加DISTINCT。尝试选择与众不同的(ed.event_id,ed.start_datetime)。有时,这些事情可以避免触发限制子查询算法。 4)关闭该系统,请参见下面的链接,从没有尝试过,并且我不确定水化和理论对象缓存有哪些副作用。 就个人而言,我会选择第一名。我发现,即使可以跨多个列形成主键,在Doctrine中使用额外的主键列也总是有帮助的。 如果要查看教义使用的代码,请参见lib / Doctrine / Record.php,函数getLimitSubquery()。您将在代码中两次注释“ //复合键?”。您还可以阅读http://www.doctrine-project.org/documentation/manual/1_2/en/dql-doctrine-query-language:limit-and-offset-clauses:the-limit-subquery-algorithm     

要回复问题请先登录注册