学说 - 获取下一条和上一条记录

doctrine - get next and prev record

所以我已经获取了一些记录。我有日期字段 'created',现在我想按日期获取下一条和上一条记录。

得到它的工作:

    $qb = $this->createQueryBuilder('a');

    $next = $qb->expr()->gt('a.created', ':date');
    $prev = $qb->expr()->lt('a.created', ':date');

    $prev = $qb->select('partial a.{id,title,created}')
        ->where($prev)
        ->setParameter('date', $date)
        ->orderBy('a.created', 'DESC')
        ->setMaxResults(1)
        ->getQuery()
        ->getArrayResult();

    $next = $qb->select('partial a.{id,title,created}')
        ->where($next)
        ->setParameter('date', $date)
        ->orderBy('a.created', 'DESC')
        ->setMaxResults(1)
        ->getQuery()
        ->getArrayResult();

效果很好。但这是对数据库的 2 个问题。我需要一个。我可以通过 join 等来做到这一点,但是当没有 next 或 prev 时,我得到的只是一个空数组。

有什么想法吗?

您可以使用本机查询来实现:

/** @var EntityManager $em */
$em = $this->getDoctrine()->getManager();
$rsm = new ResultSetMapping();
$rsm->addScalarResult('id', 'id');

$query = $em->createNativeQuery('SELECT id FROM users WHERE
        id = (SELECT id FROM users WHERE id > 2 LIMIT 1)
    OR
        id = (SELECT id FROM users WHERE id < 2 LIMIT 1)', $rsm);
$users = $query->execute();

$users 变量中,您将拥有以下数组:

[
    ['id' => 1]
    ['id' => 3]
]

此处有更多详细信息http://doctrine-orm.readthedocs.org/en/latest/reference/native-sql.html

亚历山大的回应很接近。当您查询 id < 2 LIMIT 1 时,它会 return 1,但如果您查询 id < 5 LIMIT 1,它也会 return 1。这是因为它 returns 1, 2, 3, 4 并采用第一个元素,即 1 而不是所需的 4.

只需添加 ORDER BY id DESC 即可获得上一项。这将 return 4, 3, 2, 1LIMIT 1 将 return 4 或前一个元素。

$query = $em->createNativeQuery('SELECT id FROM users WHERE
        id = (SELECT id FROM users WHERE id > 2 LIMIT 1)
        OR
        id = (SELECT id FROM users WHERE id < 2 ORDER BY id DESC LIMIT 1)', $rsm);

使用 ORM 实体存储库时本机 SQL 的替代方法。

namespace EntityNamespace;

use Doctrine\ORM\EntityRepository;

class MyEntityRepository extends EntityRepository
{

    /**
     * @param int $id
     * @return array|int[]
     */
    public function filterNextPrevious($id)
    {
        $expr = $this->_em->getExpressionBuilder();
        $qbNext = $this->createQueryBuilder('a')
           ->select(['MIN(a.id)'])
           ->where($expr->gt('a.id', ':id'));
        $qbPrevious = $this->createQueryBuilder('b')
            ->select(['MAX(b.id)'])
            ->where($expr->lt('b.id', ':id'));
        $query = $this->createQueryBuilder('m')
            ->select(['m.id'])
            ->where($expr->orX(
                $expr->eq('m.id', '(' . $qbNext->getDQL() . ')'),
                $expr->eq('m.id', '(' . $qbPrevious->getDQL() . ')')
            ))
            ->setParameter('id', $id)
            ->addOrderBy('m.id', 'ASC')
            ->getQuery();
       //optionally enable caching
       //$query->useQueryCache(true)->useResultCache(true, 3600);    

        return $query->getScalarResult();
    }
}

生成的 DQL:

SELECT m.id 
FROM EntityNamespace\Entity m 
WHERE m.id = (
    SELECT MIN(a.id) 
    FROM EntityNamespace\Entity a 
    WHERE a.id > :id
) 
OR m.id = (
    SELECT MAX(b.id) 
    FROM EntityNamespace\Entity b 
    WHERE b.id < :id
) 
ORDER BY m.id ASC

(可选择通过 $this->_em->createQuery($DQL) 使用查询生成器)

结果数据集:

array(2) {
  [0]=>
  array(1) {
    ["id"]=>
    string(4) "5869"
  }
  [1]=>
  array(1) {
    ["id"]=>
    string(4) "5871"
  }
}

使用 WHERE IN() 条件的另一种替代方法是使用 SELECT 子查询,并可选择将总数 COUNT() 添加到基础 table。

这将允许您将结果值分配给关联的键并取消 ORDER BY 子句。

$expr = $this->_em->getExpressionBuilder();
$next = $this->createQueryBuilder('a')
    ->select($expr->min('a.id'))
    ->where($expr->gt('a.id', ':id'));
$previous = $this->createQueryBuilder('b')
    ->select($expr->max('b.id'))
    ->where($expr->lt('b.id', ':id'));
$query = $this->createQueryBuilder('o')
    ->select('COUNT(o.id) as total')
    ->addSelect('(' . $previous->getDQL() . ') as previous')
    ->addSelect('(' . $next->getDQL() . ') as next')
    ->setParameter('id', $id)
    ->getQuery();

/* optionally enable caching
 * $query->useQueryCache(true)->useResultCache(true, 3600);
 */

return $query->getSingleResult();

结果 DQL:

SELECT 
    COUNT(o.id) as total, 
    (
     SELECT MAX(b.id) 
     FROM EntityNamespace\Entity b 
     WHERE b.id < :id
    ) as previous, 
    (
     SELECT MIN(a.id) 
     FROM EntityNamespace\Entity a 
     WHERE a.id > :id
    ) as next 
FROM EntityNamespace\Entity o

结果数据集:

array(3) {
    ["total"]=>
    string(4) "63156"
    ["previous"]=>
    string(4) "5869"
    ["next"]=>
    string(4) "5871"
}