学说 - 获取下一条和上一条记录
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, 1
而 LIMIT 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"
}
所以我已经获取了一些记录。我有日期字段 '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, 1
而 LIMIT 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"
}