*/ class TaskRepository extends ServiceEntityRepository { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, Task::class); } /** * Returns the max task number for a project, using an advisory lock * to prevent race conditions when creating tasks concurrently. */ public function findMaxNumberByProjectForUpdate(Project $project): int { $conn = $this->getEntityManager()->getConnection(); // Use PostgreSQL advisory lock (project ID as lock key) instead of FOR UPDATE // because FOR UPDATE is not allowed with aggregate functions in PostgreSQL. $conn->executeStatement( 'SELECT pg_advisory_xact_lock(:project)', ['project' => $project->getId()], ); $result = $conn->fetchOne( 'SELECT COALESCE(MAX(number), 0) FROM task WHERE project_id = :project', ['project' => $project->getId()], ); return (int) $result; } }