查询构建器 #
一、QueryBuilder基础 #
1.1 创建QueryBuilder #
php
<?php
namespace App\Repository;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class UserRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, User::class);
}
public function findAllActive(): array
{
return $this->createQueryBuilder('u')
->where('u.active = :active')
->setParameter('active', true)
->orderBy('u.createdAt', 'DESC')
->getQuery()
->getResult();
}
}
1.2 基本方法 #
php
<?php
class UserRepository extends ServiceEntityRepository
{
public function findByName(string $name): array
{
return $this->createQueryBuilder('u')
->select('u.id', 'u.name', 'u.email')
->where('u.name LIKE :name')
->setParameter('name', '%' . $name . '%')
->getQuery()
->getResult();
}
public function findActiveUsers(int $limit = 10): array
{
return $this->createQueryBuilder('u')
->where('u.active = :active')
->setParameter('active', true)
->setMaxResults($limit)
->getQuery()
->getResult();
}
public function countActiveUsers(): int
{
return $this->createQueryBuilder('u')
->select('COUNT(u.id)')
->where('u.active = :active')
->setParameter('active', true)
->getQuery()
->getSingleScalarResult();
}
}
二、SELECT查询 #
2.1 选择字段 #
php
<?php
class UserRepository extends ServiceEntityRepository
{
public function selectAll(): array
{
return $this->createQueryBuilder('u')
->getQuery()
->getResult();
}
public function selectSpecificFields(): array
{
return $this->createQueryBuilder('u')
->select('u.id', 'u.name', 'u.email')
->getQuery()
->getResult();
}
public function selectPartial(): array
{
return $this->createQueryBuilder('u')
->select('partial u.{id, name, email}')
->getQuery()
->getResult();
}
public function selectWithAlias(): array
{
return $this->createQueryBuilder('u')
->select('u.id as userId', 'u.name as userName')
->getQuery()
->getResult();
}
}
2.2 聚合函数 #
php
<?php
class UserRepository extends ServiceEntityRepository
{
public function countAll(): int
{
return $this->createQueryBuilder('u')
->select('COUNT(u.id)')
->getQuery()
->getSingleScalarResult();
}
public function getAverageAge(): float
{
return $this->createQueryBuilder('u')
->select('AVG(u.age)')
->getQuery()
->getSingleScalarResult();
}
public function getAgeStats(): array
{
return $this->createQueryBuilder('u')
->select('COUNT(u.id) as total')
->addSelect('AVG(u.age) as avgAge')
->addSelect('MIN(u.age) as minAge')
->addSelect('MAX(u.age) as maxAge')
->getQuery()
->getSingleResult();
}
public function groupByStatus(): array
{
return $this->createQueryBuilder('u')
->select('u.active')
->addSelect('COUNT(u.id) as count')
->groupBy('u.active')
->getQuery()
->getResult();
}
}
三、WHERE条件 #
3.1 基本条件 #
php
<?php
class UserRepository extends ServiceEntityRepository
{
public function findByStatus(bool $active): array
{
return $this->createQueryBuilder('u')
->where('u.active = :active')
->setParameter('active', $active)
->getQuery()
->getResult();
}
public function findByAgeRange(int $min, int $max): array
{
return $this->createQueryBuilder('u')
->where('u.age BETWEEN :min AND :max')
->setParameter('min', $min)
->setParameter('max', $max)
->getQuery()
->getResult();
}
public function findByNames(array $names): array
{
return $this->createQueryBuilder('u')
->where('u.name IN (:names)')
->setParameter('names', $names)
->getQuery()
->getResult();
}
public function findWithNullEmail(): array
{
return $this->createQueryBuilder('u')
->where('u.email IS NULL')
->getQuery()
->getResult();
}
}
3.2 组合条件 #
php
<?php
class UserRepository extends ServiceEntityRepository
{
public function findActiveAdults(): array
{
return $this->createQueryBuilder('u')
->where('u.active = :active')
->andWhere('u.age >= :age')
->setParameter('active', true)
->setParameter('age', 18)
->getQuery()
->getResult();
}
public function findByNameOrEmail(string $keyword): array
{
return $this->createQueryBuilder('u')
->where('u.name LIKE :keyword')
->orWhere('u.email LIKE :keyword')
->setParameter('keyword', '%' . $keyword . '%')
->getQuery()
->getResult();
}
public function findComplex(array $criteria): array
{
$qb = $this->createQueryBuilder('u');
if (isset($criteria['active'])) {
$qb->andWhere('u.active = :active')
->setParameter('active', $criteria['active']);
}
if (isset($criteria['minAge'])) {
$qb->andWhere('u.age >= :minAge')
->setParameter('minAge', $criteria['minAge']);
}
if (isset($criteria['name'])) {
$qb->andWhere('u.name LIKE :name')
->setParameter('name', '%' . $criteria['name'] . '%');
}
return $qb->getQuery()->getResult();
}
}
3.3 表达式 #
php
<?php
use Doctrine\ORM\Query\Expr;
class UserRepository extends ServiceEntityRepository
{
public function findWithExpr(): array
{
$qb = $this->createQueryBuilder('u');
return $qb
->where($qb->expr()->eq('u.active', ':active'))
->andWhere($qb->expr()->gt('u.age', ':age'))
->andWhere($qb->expr()->like('u.name', ':name'))
->setParameter('active', true)
->setParameter('age', 18)
->setParameter('name', 'John%')
->getQuery()
->getResult();
}
public function findWithOrX(): array
{
$qb = $this->createQueryBuilder('u');
return $qb
->where($qb->expr()->orX(
$qb->expr()->eq('u.role', ':admin'),
$qb->expr()->eq('u.role', ':superAdmin')
))
->setParameter('admin', 'admin')
->setParameter('superAdmin', 'super_admin')
->getQuery()
->getResult();
}
public function findWithAndX(): array
{
$qb = $this->createQueryBuilder('u');
return $qb
->where($qb->expr()->andX(
$qb->expr()->eq('u.active', ':active'),
$qb->expr()->gte('u.age', ':minAge'),
$qb->expr()->lte('u.age', ':maxAge')
))
->setParameter('active', true)
->setParameter('minAge', 18)
->setParameter('maxAge', 65)
->getQuery()
->getResult();
}
}
四、JOIN关联 #
4.1 内连接 #
php
<?php
class ArticleRepository extends ServiceEntityRepository
{
public function findWithAuthor(): array
{
return $this->createQueryBuilder('a')
->innerJoin('a.author', 'u')
->addSelect('u')
->getQuery()
->getResult();
}
public function findWithComments(): array
{
return $this->createQueryBuilder('a')
->innerJoin('a.comments', 'c')
->addSelect('c')
->where('c.status = :status')
->setParameter('status', 'approved')
->getQuery()
->getResult();
}
}
4.2 左连接 #
php
<?php
class UserRepository extends ServiceEntityRepository
{
public function findWithArticles(): array
{
return $this->createQueryBuilder('u')
->leftJoin('u.articles', 'a')
->addSelect('a')
->getQuery()
->getResult();
}
public function findUsersWithoutArticles(): array
{
return $this->createQueryBuilder('u')
->leftJoin('u.articles', 'a')
->where('a.id IS NULL')
->getQuery()
->getResult();
}
}
4.3 关联条件 #
php
<?php
class ArticleRepository extends ServiceEntityRepository
{
public function findWithPublishedComments(): array
{
return $this->createQueryBuilder('a')
->leftJoin('a.comments', 'c', 'WITH', 'c.status = :status')
->addSelect('c')
->setParameter('status', 'published')
->getQuery()
->getResult();
}
public function findWithRecentComments(): array
{
return $this->createQueryBuilder('a')
->leftJoin('a.comments', 'c', 'WITH', 'c.createdAt > :date')
->addSelect('c')
->setParameter('date', new \DateTime('-7 days'))
->getQuery()
->getResult();
}
}
五、排序和分页 #
5.1 排序 #
php
<?php
class UserRepository extends ServiceEntityRepository
{
public function findOrderedByName(): array
{
return $this->createQueryBuilder('u')
->orderBy('u.name', 'ASC')
->getQuery()
->getResult();
}
public function findOrderedByMultiple(): array
{
return $this->createQueryBuilder('u')
->orderBy('u.active', 'DESC')
->addOrderBy('u.createdAt', 'DESC')
->getQuery()
->getResult();
}
public function findWithCustomSort(string $field, string $direction = 'ASC'): array
{
return $this->createQueryBuilder('u')
->orderBy('u.' . $field, $direction)
->getQuery()
->getResult();
}
}
5.2 分页 #
php
<?php
class UserRepository extends ServiceEntityRepository
{
public function findPaginated(int $page, int $limit): array
{
return $this->createQueryBuilder('u')
->setFirstResult(($page - 1) * $limit)
->setMaxResults($limit)
->getQuery()
->getResult();
}
public function findPaginatedWithCount(int $page, int $limit): array
{
$qb = $this->createQueryBuilder('u');
$count = (clone $qb)
->select('COUNT(u.id)')
->getQuery()
->getSingleScalarResult();
$results = $qb
->setFirstResult(($page - 1) * $limit)
->setMaxResults($limit)
->getQuery()
->getResult();
return [
'items' => $results,
'total' => $count,
'page' => $page,
'limit' => $limit,
'pages' => ceil($count / $limit),
];
}
}
六、DQL查询 #
6.1 基本DQL #
php
<?php
class UserRepository extends ServiceEntityRepository
{
public function findActiveDql(): array
{
$dql = 'SELECT u FROM App\Entity\User u WHERE u.active = :active';
return $this->getEntityManager()
->createQuery($dql)
->setParameter('active', true)
->getResult();
}
public function findWithJoinDql(): array
{
$dql = '
SELECT a, u
FROM App\Entity\Article a
JOIN a.author u
WHERE a.status = :status
ORDER BY a.createdAt DESC
';
return $this->getEntityManager()
->createQuery($dql)
->setParameter('status', 'published')
->getResult();
}
}
6.2 命名查询 #
php
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
#[ORM\NamedQueries([
new ORM\NamedQuery(
name: 'User.findActive',
query: 'SELECT u FROM App\Entity\User u WHERE u.active = true ORDER BY u.name ASC'
),
new ORM\NamedQuery(
name: 'User.findByRole',
query: 'SELECT u FROM App\Entity\User u WHERE u.role = :role'
),
])]
class User
{
}
php
<?php
class UserRepository extends ServiceEntityRepository
{
public function findActiveNamed(): array
{
return $this->createNamedQuery('User.findActive')
->getResult();
}
public function findByRoleNamed(string $role): array
{
return $this->createNamedQuery('User.findByRole')
->setParameter('role', $role)
->getResult();
}
}
七、子查询 #
7.1 子查询示例 #
php
<?php
class ArticleRepository extends ServiceEntityRepository
{
public function findWithMostComments(): array
{
$subQb = $this->getEntityManager()->createQueryBuilder();
$subQuery = $subQb
->select('COUNT(c.id)')
->from('App\Entity\Comment', 'c')
->where('c.article = a.id')
->getDQL();
return $this->createQueryBuilder('a')
->select('a', '(' . $subQuery . ') as commentCount')
->orderBy('commentCount', 'DESC')
->setMaxResults(10)
->getQuery()
->getResult();
}
public function findAuthorsWithArticles(): array
{
$subQb = $this->getEntityManager()->createQueryBuilder();
$subQuery = $subQb
->select('a.author')
->from('App\Entity\Article', 'a')
->where('a.status = :status')
->getDQL();
return $this->createQueryBuilder('u')
->where($this->createQueryBuilder('u')->expr()->in('u.id', $subQuery))
->setParameter('status', 'published')
->getQuery()
->getResult();
}
}
八、原生SQL #
8.1 原生查询 #
php
<?php
class UserRepository extends ServiceEntityRepository
{
public function findByNativeSql(): array
{
$sql = 'SELECT * FROM users WHERE active = :active';
$rsm = new \Doctrine\ORM\Query\ResultSetMappingBuilder($this->getEntityManager());
$rsm->addRootEntityFromClassMetadata(User::class, 'u');
return $this->getEntityManager()
->createNativeQuery($sql, $rsm)
->setParameter('active', 1)
->getResult();
}
public function findStats(): array
{
$sql = '
SELECT
DATE(created_at) as date,
COUNT(*) as count
FROM users
WHERE created_at > :date
GROUP BY DATE(created_at)
ORDER BY date DESC
';
return $this->getEntityManager()
->getConnection()
->executeQuery($sql, ['date' => (new \DateTime('-30 days'))->format('Y-m-d')])
->fetchAllAssociative();
}
}
九、查询缓存 #
9.1 启用缓存 #
php
<?php
class UserRepository extends ServiceEntityRepository
{
public function findActiveCached(): array
{
return $this->createQueryBuilder('u')
->where('u.active = :active')
->setParameter('active', true)
->getQuery()
->enableResultCache(3600, 'active_users')
->getResult();
}
public function clearCache(): void
{
$this->getEntityManager()
->getConfiguration()
->getResultCache()
->delete('active_users');
}
}
十、总结 #
本章学习了:
- QueryBuilder基础
- SELECT查询
- WHERE条件构建
- JOIN关联查询
- 排序和分页
- DQL查询语言
- 子查询
- 原生SQL
- 查询缓存
下一章将学习 关联关系。
最后更新:2026-03-28