通过 Native Query 组合多个参数进行搜索
Search by the combination of multiple parameters via Native Query
我目前正在开发一项功能,允许系统通过 6 个参数的组合搜索 public 服务收据,这些参数可以为 null,这意味着收据不应按此参数过滤:accountNumber , amountRangeMin, amountRangeMax, dateRangeMin, dateRangeMax, publicServiceId。然而,为每个参数组合制作一个方法不是一种选择,我认为必须有更好的方法,起初我的方法如下:
在我的服务中我有这个方法:
public Map<String,Object> findPublicServiceReceiptsByParams(Integer accountNumber, BigDecimal amountRangeMin,
BigDecimal amountRangeMax, LocalDate dateRangeMin, LocalDate dateRangeMax, Integer publicServiceId) {
Map<String,Object> publicServiceReceipts = new HashMap<String,Object>();
String accountNumberFilter = !(accountNumber==null) ? accountNumber.toString() : "AccountNumberTableName";
String amountRangeMinFilter = !(amountRangeMin==null) ? amountRangeMin.toString() : "table.AmountColumnName";
String amountRangeMaxFilter = !(amountRangeMax==null) ? amountRangeMax.toString() : "table.AmountColumnName";
String dateRangeMinFilter = !(dateRangeMin==null) ? dateRangeMin.toString() : "Table.ReceiptCreationDateColumn";
String dateRangeMaxFilter = !(dateRangeMax==null) ? dateRangeMax.toString() : "Table.ReceiptCreationDateColumn";
String publicServiceIdFilter = !(publicServiceId==null) ? publicServiceId.toString() : "table.publicServiceIdColumn";
publicServiceReceipts = publicServiceReceiptRepository.findPublicServiceReceiptsByParams(accountNumberFilter,
amountRangeMinFilter, amountRangeMaxFilter, dateRangeMinFilter, dateRangeMaxFilter,
publicServiceIdFilter);
return publicServiceReceipts;
}
然后在我的存储库中我有:
final static String FIND_PUBLIC_SERVICES_BY_ARGS = "Select (Insert whatever logic should go in here to select columns from receipts the where clause is the one that matters)"
+ " WHERE ACT.ACT_AccountNumber=:accountNumberFilter\n"
+ " AND PSE.PSE_Id=:publicServiceIdFilter\n"
+ " AND PSR.PSR_CreateDate BETWEEN :dateRangeMinFilter AND :dateRangeMaxFilter\n"
+ " AND PSR.PSR_Amount BETWEEN :amountRangeMinFilter AND :amountRangeMaxFilter\n"
+ " order by PSR.PSR_CreateDate desc";
@Query(nativeQuery = true, value = FIND_PUBLIC_SERVICES_BY_ARGS)
Map<String, Object> findPublicServiceReceiptsByParams(@Param("accountNumberFilter") String accountNumberFilter,
@Param("amountRangeMinFilter") String amountRangeMinFilter,
@Param("amountRangeMaxFilter") String amountRangeMaxFilter,
@Param("dateRangeMinFilter") String dateRangeMinFilter,
@Param("dateRangeMaxFilter") String dateRangeMaxFilter,
@Param("publicServiceIdFilter") String publicServiceIdFilter);
}
我的理由是,如果参数为空,则意味着使用 Web 服务的人对该参数不感兴趣,所以如果发生这种情况,我将该变量设置为列名,这样它就不会影响 WHERE 子句理论上让它更简单,但我发现它会将名称作为字符串发送,因此它不会被识别为 sql 语句,这是我思想中的缺陷,正如我所说,必须有另一个除了为每个组合编写每个方法之外,我感谢任何帮助:)。
您应该使用专为创建动态查询而设计的 Criteria API。命名查询并不是真的要在这种情况下使用。
有了它你可以做这样的事情:
@PersistenceContext
EntityManager em;
List<YourEntity> method(String argument) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<YourEntity> cq = cb.createQuery(YourEntity.class);
Root<YourEntity> root = cq.from(YourEntity.class);
List<Predicate> predicates = new ArrayList<>();
if (argument == null) {
predicates.add(cb.equal(root.get("yourAttribute"), argument);
}
// rest of your logic goes here
cq.where(predicates.toArray(new Predicate[]{}));
return em.createQuery(cq).getResultList();
}
我找到了解决此问题的方法,我是这样做的(我将仅显示本机查询,因为这是我唯一更改的内容):
DECLARE @actNum varchar(50),@crdNum varchar(50),@pseId varchar(50),@dateMin varchar(50),@dateMax varchar(50),@amountMin varchar(50),@amountMax varchar(50)
SET @actNum = :actNum
SET @crdNum = :crdNum
SET @pseId = :pseId
SET @dateMin = :dateMin
SET @dateMax = :dateMax
SET @amountMin = :amountMin
SET @amountMax = :amountMax
--Whatever Select with joins statement
WHERE ACT.ACT_AccountNumber = CASE WHEN @actNum = 'N/A'
THEN ACT.ACT_AccountNumber
ELSE @actNum END
AND CRD_CardNumber = CASE WHEN @crdNum = 'N/A'
THEN CRD_CardNumber
ELSE @crdNum END
AND PSE.PSE_Id= CASE WHEN @pseId = 'N/A'
THEN PSE.PSE_Id
ELSE @pseId END
AND PSR.PSR_CreateDate >= CASE WHEN @dateMin = 'N/A'
THEN PSR.PSR_CreateDate
ELSE @dateMin END
AND PSR.PSR_CreateDate <= CASE WHEN @dateMax = 'N/A'
THEN PSR.PSR_CreateDate
ELSE @dateMax END
AND PSR.PSR_Amount BETWEEN CASE WHEN @amountMin = 'N/A'
THEN PSR.PSR_Amount
ELSE @amountMin END
AND CASE WHEN @amountMax = 'N/A'
THEN PSR.PSR_Amount
ELSE @amountMax END
ORDER BY PSR.PSR_CreateDate DESC
后端将发送参数作为 "N/A"(如果它不应该用于过滤数据)或实际值,这对我来说很好!
我目前正在开发一项功能,允许系统通过 6 个参数的组合搜索 public 服务收据,这些参数可以为 null,这意味着收据不应按此参数过滤:accountNumber , amountRangeMin, amountRangeMax, dateRangeMin, dateRangeMax, publicServiceId。然而,为每个参数组合制作一个方法不是一种选择,我认为必须有更好的方法,起初我的方法如下:
在我的服务中我有这个方法:
public Map<String,Object> findPublicServiceReceiptsByParams(Integer accountNumber, BigDecimal amountRangeMin,
BigDecimal amountRangeMax, LocalDate dateRangeMin, LocalDate dateRangeMax, Integer publicServiceId) {
Map<String,Object> publicServiceReceipts = new HashMap<String,Object>();
String accountNumberFilter = !(accountNumber==null) ? accountNumber.toString() : "AccountNumberTableName";
String amountRangeMinFilter = !(amountRangeMin==null) ? amountRangeMin.toString() : "table.AmountColumnName";
String amountRangeMaxFilter = !(amountRangeMax==null) ? amountRangeMax.toString() : "table.AmountColumnName";
String dateRangeMinFilter = !(dateRangeMin==null) ? dateRangeMin.toString() : "Table.ReceiptCreationDateColumn";
String dateRangeMaxFilter = !(dateRangeMax==null) ? dateRangeMax.toString() : "Table.ReceiptCreationDateColumn";
String publicServiceIdFilter = !(publicServiceId==null) ? publicServiceId.toString() : "table.publicServiceIdColumn";
publicServiceReceipts = publicServiceReceiptRepository.findPublicServiceReceiptsByParams(accountNumberFilter,
amountRangeMinFilter, amountRangeMaxFilter, dateRangeMinFilter, dateRangeMaxFilter,
publicServiceIdFilter);
return publicServiceReceipts;
}
然后在我的存储库中我有:
final static String FIND_PUBLIC_SERVICES_BY_ARGS = "Select (Insert whatever logic should go in here to select columns from receipts the where clause is the one that matters)"
+ " WHERE ACT.ACT_AccountNumber=:accountNumberFilter\n"
+ " AND PSE.PSE_Id=:publicServiceIdFilter\n"
+ " AND PSR.PSR_CreateDate BETWEEN :dateRangeMinFilter AND :dateRangeMaxFilter\n"
+ " AND PSR.PSR_Amount BETWEEN :amountRangeMinFilter AND :amountRangeMaxFilter\n"
+ " order by PSR.PSR_CreateDate desc";
@Query(nativeQuery = true, value = FIND_PUBLIC_SERVICES_BY_ARGS)
Map<String, Object> findPublicServiceReceiptsByParams(@Param("accountNumberFilter") String accountNumberFilter,
@Param("amountRangeMinFilter") String amountRangeMinFilter,
@Param("amountRangeMaxFilter") String amountRangeMaxFilter,
@Param("dateRangeMinFilter") String dateRangeMinFilter,
@Param("dateRangeMaxFilter") String dateRangeMaxFilter,
@Param("publicServiceIdFilter") String publicServiceIdFilter);
}
我的理由是,如果参数为空,则意味着使用 Web 服务的人对该参数不感兴趣,所以如果发生这种情况,我将该变量设置为列名,这样它就不会影响 WHERE 子句理论上让它更简单,但我发现它会将名称作为字符串发送,因此它不会被识别为 sql 语句,这是我思想中的缺陷,正如我所说,必须有另一个除了为每个组合编写每个方法之外,我感谢任何帮助:)。
您应该使用专为创建动态查询而设计的 Criteria API。命名查询并不是真的要在这种情况下使用。 有了它你可以做这样的事情:
@PersistenceContext
EntityManager em;
List<YourEntity> method(String argument) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<YourEntity> cq = cb.createQuery(YourEntity.class);
Root<YourEntity> root = cq.from(YourEntity.class);
List<Predicate> predicates = new ArrayList<>();
if (argument == null) {
predicates.add(cb.equal(root.get("yourAttribute"), argument);
}
// rest of your logic goes here
cq.where(predicates.toArray(new Predicate[]{}));
return em.createQuery(cq).getResultList();
}
我找到了解决此问题的方法,我是这样做的(我将仅显示本机查询,因为这是我唯一更改的内容):
DECLARE @actNum varchar(50),@crdNum varchar(50),@pseId varchar(50),@dateMin varchar(50),@dateMax varchar(50),@amountMin varchar(50),@amountMax varchar(50)
SET @actNum = :actNum
SET @crdNum = :crdNum
SET @pseId = :pseId
SET @dateMin = :dateMin
SET @dateMax = :dateMax
SET @amountMin = :amountMin
SET @amountMax = :amountMax
--Whatever Select with joins statement
WHERE ACT.ACT_AccountNumber = CASE WHEN @actNum = 'N/A'
THEN ACT.ACT_AccountNumber
ELSE @actNum END
AND CRD_CardNumber = CASE WHEN @crdNum = 'N/A'
THEN CRD_CardNumber
ELSE @crdNum END
AND PSE.PSE_Id= CASE WHEN @pseId = 'N/A'
THEN PSE.PSE_Id
ELSE @pseId END
AND PSR.PSR_CreateDate >= CASE WHEN @dateMin = 'N/A'
THEN PSR.PSR_CreateDate
ELSE @dateMin END
AND PSR.PSR_CreateDate <= CASE WHEN @dateMax = 'N/A'
THEN PSR.PSR_CreateDate
ELSE @dateMax END
AND PSR.PSR_Amount BETWEEN CASE WHEN @amountMin = 'N/A'
THEN PSR.PSR_Amount
ELSE @amountMin END
AND CASE WHEN @amountMax = 'N/A'
THEN PSR.PSR_Amount
ELSE @amountMax END
ORDER BY PSR.PSR_CreateDate DESC
后端将发送参数作为 "N/A"(如果它不应该用于过滤数据)或实际值,这对我来说很好!