Spring boot: Query方法中的可选参数查询
Spring boot: Optional parameter query in Query method
我是 Spring 引导和休眠的新手。在这里,我正在尝试 运行 基于搜索的可选参数查询,我可以在其中按名称、国家/地区等进行搜索。如果我将此字段保留为空,则查询应该全部列出。但问题是我的方法返回的所有数据都忽略了我的搜索参数。我的模型 class 看起来像
@Entity(name="MLFM_ORDER_OWNER")
public class ModelOrderOwner {
@Id @GenericGenerator(name = "custom_sequence", strategy =
"com.biziitech.mlfm.IdGenerator")
@GeneratedValue(generator = "custom_sequence")
@Column(name="ORDER_OWNER_ID")
private Long orderOwnerId;
@Column(name="OWNER_NAME")
private String ownerName;
@OneToOne
@JoinColumn(name="BUSINESS_TYPE_ID")
private ModelBusinessType businessTypeId;
@Column(name="SHORT_CODE")
private String shortCode;
@ManyToOne
@JoinColumn(name="OWNER_COUNTRY")
private ModelCountry ownerCountry;
// getter setter..
我的存储库界面看起来像
public interface OrderOwnerRepository extends
JpaRepository<ModelOrderOwner,Long>{
@Query("select a from MLFM_ORDER_OWNER a where a.businessTypeId.typeId=coalsec(:typeId,a.businessTypeId.typeId) and a.ownerCountry.countryId=coalsec(:countryId,a.ownerCountry.countryId) and a.ownerName LIKE %:name and a.shortCode LIKE %:code")
public List <ModelOrderOwner> findOwnerDetails(@Param("typeId")Long typeId,@Param("countryId")Long countryId,@Param("name")String name,@Param("code")String code);
}
这是我在控制器中的方法
@RequestMapping(path="/owners/search")
public String getAllOwner(Model model,@RequestParam("owner_name") String name,@RequestParam("shortCode") String code,
@RequestParam("phoneNumber") String phoneNumber,@RequestParam("countryName") Long countryId,
@RequestParam("businessType") Long typeId
) {
model.addAttribute("ownerList",ownerRepository.findOwnerDetails(typeId, countryId, name, code));
return "data_list";
}
在这方面有人可以帮助我吗?请问?
JPQL 不支持可选参数。
在 JPQL 中没有简单的方法可以做到这一点。您将不得不使用 OR 运算符编写多个 WHERE 子句。
参考这些类似问题的答案:Answer 1 & Answer 2
PS:您可能希望针对您的用例查看 Query by Example。它支持空参数的处理。
不知道如何,但下面的代码对我有用:
@Query("select a from MLFM_ORDER_OWNER a
where a.businessTypeId.typeId=COALESCE(:typeId,a.businessTypeId.typeId)
and a.ownerCountry.countryId=COALESCE(:countryId,a.ownerCountry.countryId)
and a.ownerName LIKE %:name and a.shortCode LIKE %:code")
public List <ModelOrderOwner> findOwnerDetails(
@Param("typeId")Long typeId,
@Param("countryId")Long countryId,
@Param("name")String name,
@Param("code")String code);
在我的控制器中 class:
@RequestMapping(path="/owners/search")
public String getAllOwner(Model model,
@RequestParam("owner_name") String name,
@RequestParam("shortCode") String code,
@RequestParam("phoneNumber") String phoneNumber,
@RequestParam("countryName") Long countryId,
@RequestParam(value = "active", required = false) String active, @RequestParam("businessType") Long typeId) {
if(typeId==0)
typeId=null;
if(countryId==0)
countryId=null; model.addAttribute("ownerList",ownerRepository.findOwnerDetails(typeId, countryId, name, code, status));
return "data_list";
}
使用JpaSpecificationExecutor
//import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
步骤 1:在您的 JPA 存储库中实施 JpaSpecificationExecutor
例如:
public interface TicketRepo extends JpaRepository<Ticket, Long>, JpaSpecificationExecutor<Ticket> {
步骤 2 现在要根据可选参数获取票证,您可以使用 CriteriaBuilder
构建规范查询
例如:
public Specification<Ticket> getTicketQuery(Integer domainId, Calendar startDate, Calendar endDate, Integer gameId, Integer drawId) {
return (root, query, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
predicates.add(criteriaBuilder.equal(root.get("domainId"), domainId));
predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createdAt"), startDate));
predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("createdAt"), endDate));
if (gameId != null) {
predicates.add(criteriaBuilder.equal(root.get("gameId"), gameId));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
};
}
第 3 步:将 Specification 实例传递给 jpaRepo.findAll(specification),它将 return 您的实体对象列表(运行 示例中的 Tickets)
ticketRepo.findAll(specification); // Pass output of function in step 2 to findAll
现在回答也太晚了,但是对于任何正在寻找解决方案的人来说,还有一个更简单的方法如下:
在我的例子中,我的控制器是这样的:
@RestController
@RequestMapping("/order")
public class OrderController {
private final IOrderService service;
public OrderController(IOrderService service) {
this.service = service;
}
@RequestMapping(value = "/{username}/", method = RequestMethod.GET)
public ResponseEntity<ListResponse<UserOrdersResponse>> getUserOrders(
@RequestHeader Map<String, String> requestHeaders,
@RequestParam(required=false) Long id,
@RequestParam(required=false) Long flags,
@RequestParam(required=true) Long offset,
@RequestParam(required=true) Long length) {
// Return successful response
return new ResponseEntity<>(service.getUserOrders(requestDTO), HttpStatus.OK);
}
}
如您所见,我有 Username
作为 @PathVariable
和 length
和 offset
是我需要的参数,但我接受 id
和flags
用于过滤搜索结果,所以它们是我的可选参数,调用 REST 服务时不需要。
现在在我的存储库层中,我刚刚创建了我的 @Query
,如下所示:
@Query("select new com.ada.bourse.wealth.services.models.response.UserOrdersResponse(FIELDS ARE DELETED TO BECOME MORE READABLE)" +
" from User u join Orders o on u.id = o.user.id where u.userName = :username" +
" and (:orderId is null or o.id = :orderId) and (:flag is null or o.flags = :flag)")
Page<UserOrdersResponse> findUsersOrders(String username, Long orderId, Long flag, Pageable page);
就是这样,你可以看到我用 (:orderId is null or o.id = :orderId)
和 (:flag is null or o.flags = :flag)
检查了我的可选参数,我认为需要强调的是 我检查了我的参数 条件 不是我的列数据 ,所以如果客户端为我发送 Id
和 flags
参数,我将用它们过滤结果否则我只是用 username
查询这是我的 @PathVariable
.
我是 Spring 引导和休眠的新手。在这里,我正在尝试 运行 基于搜索的可选参数查询,我可以在其中按名称、国家/地区等进行搜索。如果我将此字段保留为空,则查询应该全部列出。但问题是我的方法返回的所有数据都忽略了我的搜索参数。我的模型 class 看起来像
@Entity(name="MLFM_ORDER_OWNER")
public class ModelOrderOwner {
@Id @GenericGenerator(name = "custom_sequence", strategy =
"com.biziitech.mlfm.IdGenerator")
@GeneratedValue(generator = "custom_sequence")
@Column(name="ORDER_OWNER_ID")
private Long orderOwnerId;
@Column(name="OWNER_NAME")
private String ownerName;
@OneToOne
@JoinColumn(name="BUSINESS_TYPE_ID")
private ModelBusinessType businessTypeId;
@Column(name="SHORT_CODE")
private String shortCode;
@ManyToOne
@JoinColumn(name="OWNER_COUNTRY")
private ModelCountry ownerCountry;
// getter setter..
我的存储库界面看起来像
public interface OrderOwnerRepository extends
JpaRepository<ModelOrderOwner,Long>{
@Query("select a from MLFM_ORDER_OWNER a where a.businessTypeId.typeId=coalsec(:typeId,a.businessTypeId.typeId) and a.ownerCountry.countryId=coalsec(:countryId,a.ownerCountry.countryId) and a.ownerName LIKE %:name and a.shortCode LIKE %:code")
public List <ModelOrderOwner> findOwnerDetails(@Param("typeId")Long typeId,@Param("countryId")Long countryId,@Param("name")String name,@Param("code")String code);
}
这是我在控制器中的方法
@RequestMapping(path="/owners/search")
public String getAllOwner(Model model,@RequestParam("owner_name") String name,@RequestParam("shortCode") String code,
@RequestParam("phoneNumber") String phoneNumber,@RequestParam("countryName") Long countryId,
@RequestParam("businessType") Long typeId
) {
model.addAttribute("ownerList",ownerRepository.findOwnerDetails(typeId, countryId, name, code));
return "data_list";
}
在这方面有人可以帮助我吗?请问?
JPQL 不支持可选参数。 在 JPQL 中没有简单的方法可以做到这一点。您将不得不使用 OR 运算符编写多个 WHERE 子句。
参考这些类似问题的答案:Answer 1 & Answer 2
PS:您可能希望针对您的用例查看 Query by Example。它支持空参数的处理。
不知道如何,但下面的代码对我有用:
@Query("select a from MLFM_ORDER_OWNER a
where a.businessTypeId.typeId=COALESCE(:typeId,a.businessTypeId.typeId)
and a.ownerCountry.countryId=COALESCE(:countryId,a.ownerCountry.countryId)
and a.ownerName LIKE %:name and a.shortCode LIKE %:code")
public List <ModelOrderOwner> findOwnerDetails(
@Param("typeId")Long typeId,
@Param("countryId")Long countryId,
@Param("name")String name,
@Param("code")String code);
在我的控制器中 class:
@RequestMapping(path="/owners/search")
public String getAllOwner(Model model,
@RequestParam("owner_name") String name,
@RequestParam("shortCode") String code,
@RequestParam("phoneNumber") String phoneNumber,
@RequestParam("countryName") Long countryId,
@RequestParam(value = "active", required = false) String active, @RequestParam("businessType") Long typeId) {
if(typeId==0)
typeId=null;
if(countryId==0)
countryId=null; model.addAttribute("ownerList",ownerRepository.findOwnerDetails(typeId, countryId, name, code, status));
return "data_list";
}
使用JpaSpecificationExecutor
//import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
步骤 1:在您的 JPA 存储库中实施 JpaSpecificationExecutor
例如:
public interface TicketRepo extends JpaRepository<Ticket, Long>, JpaSpecificationExecutor<Ticket> {
步骤 2 现在要根据可选参数获取票证,您可以使用 CriteriaBuilder
构建规范查询例如:
public Specification<Ticket> getTicketQuery(Integer domainId, Calendar startDate, Calendar endDate, Integer gameId, Integer drawId) {
return (root, query, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
predicates.add(criteriaBuilder.equal(root.get("domainId"), domainId));
predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createdAt"), startDate));
predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("createdAt"), endDate));
if (gameId != null) {
predicates.add(criteriaBuilder.equal(root.get("gameId"), gameId));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
};
}
第 3 步:将 Specification 实例传递给 jpaRepo.findAll(specification),它将 return 您的实体对象列表(运行 示例中的 Tickets)
ticketRepo.findAll(specification); // Pass output of function in step 2 to findAll
现在回答也太晚了,但是对于任何正在寻找解决方案的人来说,还有一个更简单的方法如下:
在我的例子中,我的控制器是这样的:
@RestController
@RequestMapping("/order")
public class OrderController {
private final IOrderService service;
public OrderController(IOrderService service) {
this.service = service;
}
@RequestMapping(value = "/{username}/", method = RequestMethod.GET)
public ResponseEntity<ListResponse<UserOrdersResponse>> getUserOrders(
@RequestHeader Map<String, String> requestHeaders,
@RequestParam(required=false) Long id,
@RequestParam(required=false) Long flags,
@RequestParam(required=true) Long offset,
@RequestParam(required=true) Long length) {
// Return successful response
return new ResponseEntity<>(service.getUserOrders(requestDTO), HttpStatus.OK);
}
}
如您所见,我有 Username
作为 @PathVariable
和 length
和 offset
是我需要的参数,但我接受 id
和flags
用于过滤搜索结果,所以它们是我的可选参数,调用 REST 服务时不需要。
现在在我的存储库层中,我刚刚创建了我的 @Query
,如下所示:
@Query("select new com.ada.bourse.wealth.services.models.response.UserOrdersResponse(FIELDS ARE DELETED TO BECOME MORE READABLE)" +
" from User u join Orders o on u.id = o.user.id where u.userName = :username" +
" and (:orderId is null or o.id = :orderId) and (:flag is null or o.flags = :flag)")
Page<UserOrdersResponse> findUsersOrders(String username, Long orderId, Long flag, Pageable page);
就是这样,你可以看到我用 (:orderId is null or o.id = :orderId)
和 (:flag is null or o.flags = :flag)
检查了我的可选参数,我认为需要强调的是 我检查了我的参数 条件 不是我的列数据 ,所以如果客户端为我发送 Id
和 flags
参数,我将用它们过滤结果否则我只是用 username
查询这是我的 @PathVariable
.