@Query("SELECT new com.api.projection.GarageVehicleRequestLookupProjection" +
"(vr.id, vr.appUser.fullName, vr.appUser.unit.id, vr.appUser.unit.name, vr.createdAt, " +
"vr.startAt, vr.endAt, vr.destination,vr.reason, vr.assignedVehicle.id, " +
"vr.assignedVehicle.plate, vr.latestAction.vehicleRequestStatus,vr.appUser.unit.director.id, vr.appUser.unit.director.fullName,vr.driverRequested," +
"vr.garage.name, vr.vehicleTypeRequested, vr.requestType, vr.description, vr.assignedVehicleDriver.id, vr.assignedVehicleDriver.fullName)" +
" FROM VehicleRequest AS vr " +
"WHERE " +
"vr.appUser.fullName like %:fullName% " +
"AND (coalesce(:unitIds, null) is null or vr.appUser.unit.id in :unitIds) " +
"AND (coalesce(:garageIds, null) is null or vr.garage.id in :garageIds) " +
"AND (coalesce(:vehicleIds, null) is null or vr.assignedVehicle.id in :vehicleIds) " +
"AND (coalesce(:statuses, null) is null or vr.latestAction.vehicleRequestStatus in :statuses) " +
"AND (coalesce(:createdAt, null) is null or cast(:createdAt as date) = cast(vr.createdAt as date)) " +
"AND vr.startAt >= :startAt and vr.startAt <= :startAtEnd ")
Page<GarageVehicleRequestLookupProjection> getGarageVehicleRequestsWithFilter(
@Param("fullName") String fullName,
@Param("unitIds") List<Long> unitIds,
@Param("garageIds") List<Long> garageIds,
@Param("vehicleIds") List<Long> vehicleIds,
@Param("statuses") List<VehicleRequestStatus> status,
@Param("createdAt") Date createdAt,
@Param("startAt") Date startAt, @Param("startAtEnd") Date startAtEnd,
Pageable pageable);
VehicleRequest
表中有146条记录。当我运行上面的hql语句时,如果vr.assignedVehicle
为空,则不会返回记录,因此我得到36条记录,因为只有这些记录具有assignedVehicle
(assignedVehicleId)。
当我不像这样做投影的时候,
SELECT vr FROM VehicleRequest AS vr ...
所有的记录都将被返回。上述方法的问题是有太多的连接,因此JPA对数据库发出太多的请求。
这是在删除了一些不必要的条件后生成的语句,
select vehiclereq0_.id as col_0_0_,
appuser1_.full_name as col_1_0_,
appuser1_.unit_id as col_2_0_,
unit4_.name as col_3_0_,
vehiclereq0_.created_at as col_4_0_,
vehiclereq0_.start_at as col_5_0_,
vehiclereq0_.end_at as col_6_0_,
vehiclereq0_.destination as col_7_0_,
vehiclereq0_.reason as col_8_0_,
vehiclereq0_.assigned_vehicle_id as col_9_0_,
vehicle5_.plate as col_10_0_,
vehiclereq6_.vehicle_request_status as col_11_0_,
unit4_.director_id as col_12_0_,
appuser11_.full_name as col_13_0_,
vehiclereq0_.driver_requested as col_14_0_,
garage12_.name as col_15_0_,
vehiclereq0_.vehicle_type_requested as col_16_0_,
vehiclereq0_.request_type as col_17_0_,
vehiclereq0_.description as col_18_0_,
vehiclereq0_.assigned_vehicle_driver_id as col_19_0_,
appuser13_.full_name as col_20_0_
from vehicle_request vehiclereq0_
cross join app_user appuser1_
cross join unit unit4_
cross join app_user appuser11_
cross join vehicle vehicle5_
cross join vehicle_request_action vehiclereq6_
cross join garage garage12_
cross join app_user appuser13_
where vehiclereq0_.app_user_id = appuser1_.id
and appuser1_.unit_id = unit4_.id
and unit4_.director_id = appuser11_.id
and vehiclereq0_.latest_action_id = vehiclereq6_.id
and vehiclereq0_.garage = garage12_.id
and vehiclereq0_.assigned_vehicle_driver_id = appuser13_.id
and vehiclereq0_.assigned_vehicle_id = vehicle5_.id
and (coalesce(null, null) is null or appuser1_.unit_id in (null))
and (coalesce(null, null) is null or vehiclereq0_.garage in (null))
and (coalesce(null, null) is null or vehiclereq0_.assigned_vehicle_id in (null))
and (coalesce(null, null) is null or vehiclereq6_.vehicle_request_status in (null))
order by vehiclereq0_.created_at desc
这些语句可以为空,
and vehiclereq0_.assigned_vehicle_driver_id = appuser13_.id
and vehiclereq0_.assigned_vehicle_id = vehicle5_.id
1条答案
按热度按时间628mspwn1#
简而言之,这就是HQL的工作方式。内连接语义是路径表达式的默认语义。如果需要左连接语义,则必须显式地编写连接。
我认为,这是Blaze-Persistence实体视图的一个完美用例,因为JPA/Hibernate上的这个库默认为路径保留了连接语义。
我创建这个库是为了允许在JPA模型和自定义接口或抽象类定义的模型之间进行简单的Map,就像Spring Data Projections一样。其思想是您可以按照自己喜欢的方式定义目标结构(域模型),并通过JPQL表达式将属性(getter)Map到实体模型。
使用Blaze-Persistence Entity-Views时,您的用例的DTO模型可能如下所示:
查询是将实体视图应用于查询的问题,最简单的是按id查询。
GarageVehicleRequestLookupProjection a = entityViewManager.find(entityManager, GarageVehicleRequestLookupProjection.class, id);
Spring Data 集成允许您像Spring Data 投影一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
最好的部分是,它将只获取实际需要的状态,类似于您的自定义查询!
使用Spring Data JPA规范或
EntityViewSettingProcessor
,您还可以更高效地实现过滤:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features