无法将带子查询的Query转换为Symfony Doctrine QueryBuilder

时间:2018-02-09 14:56:54

标签: symfony doctrine-orm

我有一个执行所需操作的查询

SELECT v.* FROM vehicle v 
WHERE v.company_id = 2 AND v.id NOT IN
    (
        SELECT h.vehicle_id
        FROM hire h
        WHERE
        h.start_date is not null and h.end_date is null
    )

所以现在我想在Symfony / Doctrine

中编写这个查询

我有这个

$qb   = $this->_em->createQueryBuilder();
$subq = $this->_em->createQueryBuilder();

$subq   ->select('h.vehicle')
        ->from('AppBundle\Entity\Hire', 'h')
        ->andWhere('h.startDate is not null and h.endDate is null');

$qb->select('v')
        ->from('AppBundle\Entity\Vehicle', 'v')
        ->where($qb->expr()->notIn('v.id',$subq->getDQL()))
        ->andWhere('v.company = :company')
        ->setParameter('company', $company)
        ->orderBy('v.registrationNumber', 'ASC')
    ;
$t = $qb->getDQL();

return $qb;

如你所见,我试图转储DQL,看看是否给了我任何线索,这是

SELECT v 
FROM AppBundle\Entity\Vehicle v 
WHERE (v.id NOT IN(SELECT h.vehicle FROM AppBundle\Entity\Hire h WHERE h.startDate is not null and h.endDate is null)) 
AND v.company = :company 
ORDER BY v.registrationNumber ASC

我尝试将其转换回简单的SQL,即删除AppBundle并将列名转换回实际的列名,然后运行并获得正确的结果。

但我收到此错误

  

学说\ ORM \查询\ QueryException:   [语义错误]第0行,第69行附近'车辆FROM':错误:无效的PathExpression。必须是StateFieldPathExpression。

     

在vendor \ doctrine \ orm \ lib \ Doctrine \ ORM \ Query \ QueryException.php:63     在Doctrine \ ORM \ Query \ QueryException :: semanticalError('第0行,第69行附近\' vehicle FROM \':错误:无效的PathExpression。必须是StateFieldPathExpression。',对象(QueryException))

涉及的2个表是

CREATE TABLE `hire` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `company_id` int(11) DEFAULT NULL,
  `driver_id` int(11) DEFAULT NULL,
  `vehicle_id` int(11) DEFAULT NULL,
  `corporate_hire` tinyint(1) DEFAULT NULL,
  `end_date` datetime DEFAULT NULL,
  `end_miles` decimal(10,1) DEFAULT NULL,
  `start_date` datetime DEFAULT NULL,
  `start_miles` decimal(10,1) DEFAULT NULL,
  `created_by` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `updated_by` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `deleted_by` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `deleted_at` datetime DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_B8017EFC979B1AD6` (`company_id`),
  KEY `IDX_B8017EFCC3423909` (`driver_id`),
  KEY `IDX_B8017EFC545317D1` (`vehicle_id`),
  CONSTRAINT `FK_B8017EFC545317D1` FOREIGN KEY (`vehicle_id`) REFERENCES `vehicle` (`id`) ON DELETE SET NULL,
  CONSTRAINT `FK_B8017EFC979B1AD6` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`) ON DELETE SET NULL,
  CONSTRAINT `FK_B8017EFCC3423909` FOREIGN KEY (`driver_id`) REFERENCES `driver` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE `vehicle` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `company_id` int(11) DEFAULT NULL,
  `storage_id` int(11) DEFAULT NULL,
  `created_by` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `updated_by` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `deleted_by` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `deleted_at` datetime DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  `date_of_manufacture` datetime DEFAULT NULL,
  `engine_size` int(11) DEFAULT NULL,
  `make` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `model` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `registration_number` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
  `vin` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_1B80E486979B1AD6` (`company_id`),
  KEY `IDX_1B80E4865CC5DB90` (`storage_id`),
  CONSTRAINT `FK_1B80E4865CC5DB90` FOREIGN KEY (`storage_id`) REFERENCES `storage` (`id`) ON DELETE SET NULL,
  CONSTRAINT `FK_1B80E486979B1AD6` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

我不确定Invalid Path Expression应该让我将其视为实际错误。

  

FIX:只是像这样添加IDENTITY()

$subq   ->select('IDENTITY(h.vehicle)')

1 个答案:

答案 0 :(得分:2)

为我们工作的是(适合您的示例,因此未经测试):

$subQuery->select('IDENTITY(h.vehicle)');
$subQuery->from('AppBundle\Entity\Hire', 'h');

$dqlString = $subQuery->getQuery()->getDQL();

$query->andWhere('v.id' 'NOT IN (' . $dqlString . ')');

我看到的唯一两个不同之处是:

  1. subQuery返回h.vehicle的IDENTITY(),因此只有'标识符' (大多数情况下 id
  2. 我们在主查询中的andWhere条件是手动创建的 - 但您的表达式构建器应该以相同的方式工作。
  3. 所以我的假设是你的$subq ->select('h.vehicle')没有返回 id ,可以在主查询的NOT IN条件中使用,这可能会被你解决DQL SELECT v:这将返回所有字段,但您只需要 v.id