Doctrine按年倒序查询DateTimeImmutable字段当年最新记录
查询指定年份最后一条入库记录的修复方案
原有代码的问题点
- 核心匹配逻辑错误:
createdAt字段存储的是完整日期时间格式(如2023-11-15 14:23:05),直接用d.createdAt = :year和年份数字(如2023)做等值匹配,永远无法命中有效记录,这是返回空数组的主要原因。 - 存在语法笔误:初始化
$year的代码行末尾多了无意义的句点,会触发PHP语法解析错误。 - 排序逻辑偏差:原代码按传入的业务字段
numeroDevis倒序,无法保证取到的是当年最后一条入库的记录,除非该字段是严格随入库时间递增的自增字段。 - 结果获取方式冗余:查询明确限制只返回1条结果,用
getResult()返回数组还需要额外取元素,不符合场景需求。
修复后的实现代码
调用侧代码
$column = "numeroDevis"; // 修正原代码的语法笔误,直接获取当前年份的数字值 $year = (new DateTimeImmutable('now'))->format('Y'); // 调用查询方法 $lastEntry = $this->getRepository(YourEntity::class)->findLastEntryFromThisYear($column, (int)$year);
仓库类查询方法
public function findLastEntryFromThisYear(string $column, int $year): ?object { // 生成目标年份的起止时间范围,用范围查询替代年份函数匹配 $yearStart = new DateTimeImmutable(sprintf('%d-01-01 00:00:00', $year)); $yearEnd = $yearStart->modify('+1 year'); return $this->createQueryBuilder('d') ->where('d.createdAt >= :yearStart') ->andWhere('d.createdAt < :yearEnd') ->andWhere(sprintf('d.%s IS NOT NULL', $column)) ->setParameter('yearStart', $yearStart) ->setParameter('yearEnd', $yearEnd) // 按创建时间倒序,确保第一条就是当年最新入库的记录 ->orderBy('d.createdAt', 'DESC') ->setMaxResults(1) ->getQuery() // 单条查询直接返回实体对象,无匹配时返回null ->getOneOrNullResult() ; }
优化说明
- 采用时间范围匹配替代
YEAR(d.createdAt) = :year的函数查询写法,可命中createdAt字段的数据库索引,数据量大时查询性能提升明显。 - 增加参数类型声明,从语法层面避免传入非法格式的参数。
- 用
getOneOrNullResult()替代getResult(),直接返回单条实体或null,省去后续数组判断的冗余代码。
内容的提问来源于stack exchange,提问作者René Wetta
相关产品推荐
相关产品推荐

