java - 创建动态 JPA 查询
问题描述
我有一个包含许多字段作为查询过滤器的视图,并且我正在使用 JPA 派生查询,但是为字段/过滤器的每个组合创建所有查询将是乏味且冗长的。
我发现我可以为它创建一个动态查询,但不确定如何。
到目前为止,我已经在我的存储库中创建了这些查询,但还需要更多:
public interface EmployeeReportInfoViewRepository extends PagingAndSortingRepository<EmployeeReportInfo, Long> {
List<EmployeeReportInfo> findByControlNumber(String controlNmber);
List<EmployeeReportInfo> findByManager(String manager);
List<EmployeeReportInfo> findByofficeLocation(String officeLocation);
List<EmployeeReportInfo> findByBenchFlag(char benchFlag);
List<EmployeeReportInfo> findByBillableFlag(char billableFlag);
List<EmployeeReportInfo> findByEnableFlag(boolean enableFlag);
List<EmployeeReportInfo> findByLastNameAndFirstNameAndControlNumber(String lastName, String firstName,String controlNumber);
List<EmployeeReportInfo> findByLastNameAndFirstNameAndControlNumberAndManager(String lastName, String firstName,String controlNmber,String manager);
List<EmployeeReportInfo> findByLastNameAndFirstNameAndControlNumberAndManagerAndOfficeLocation(String lastName, String firstName,String controlNmber,String manager,String officeLocation);
List<EmployeeReportInfo> findByLastNameAndFirstNameAndControlNumberAndManagerAndOfficeLocationAndBenchFlag(String lastName, String firstName,String controlNmber,String manager,String officeLocation, char benchFlag);
List<EmployeeReportInfo> findByLastNameAndFirstNameAndControlNumberAndManagerAndOfficeLocationAndBenchFlagAndBillableFlag(String lastName, String firstName,String controlNmber,String manager,String officeLocation, char benchFlag,char bllableFlag);
List<EmployeeReportInfo> findByLastNameAndFirstNameAndControlNumberAndManagerAndOfficeLocationAndBenchFlagAndBillableFlagAndEnableFlagAndStartGreaterThanEqualAndEndLessThanEqual
(String lastName, String firstName,String controlNmber,String manager,String officeLocation, char benchFlag,char bllableFlag,
boolean emableFlag, Date start,Date end);
}
@Entity
@Table(name = "employee_report_view")
public class EmployeeReportInfo {
@Id
@Column(name = "employee_id")
private Long id;
private String name;
private Date start;
private Date end;
@Column(name = "control_number")
private String controlNumber;
@Column(name = "enable_flag")
private boolean enableFlag;
@Column(name = "billable_flag")
private char billableFlag;
@Column(name = "bench_flag")
private char benchFlag;
@Column(name = "office_location")
private String officeLocation;
@Column(name = "manager")
private String manager;
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @param id the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the start
*/
public Date getStart() {
return start;
}
/**
* @param start the start to set
*/
public void setStart(Date start) {
this.start = start;
}
/**
* @return the end
*/
public Date getEnd() {
return end;
}
/**
* @param end the end to set
*/
public void setEnd(Date end) {
this.end = end;
}
/**
* @return the controlNumber
*/
public String getControlNumber() {
return controlNumber;
}
/**
* @param controlNumber the controlNumber to set
*/
public void setControlNumber(String controlNumber) {
this.controlNumber = controlNumber;
}
/**
* @return the enableFlag
*/
public boolean isEnableFlag() {
return enableFlag;
}
/**
* @param enableFlag the enableFlag to set
*/
public void setEnableFlag(boolean enableFlag) {
this.enableFlag = enableFlag;
}
/**
* @return the billableFlag
*/
public char getBillableFlag() {
return billableFlag;
}
/**
* @param billableFlag the billableFlag to set
*/
public void setBillableFlag(char billableFlag) {
this.billableFlag = billableFlag;
}
/**
* @return the benchFlag
*/
public char getBenchFlag() {
return benchFlag;
}
/**
* @param benchFlag the benchFlag to set
*/
public void setBenchFlag(char benchFlag) {
this.benchFlag = benchFlag;
}
/**
* @return the officeLocation
*/
public String getOfficeLocation() {
return officeLocation;
}
/**
* @param officeLocation the officeLocation to set
*/
public void setOfficeLocation(String officeLocation) {
this.officeLocation = officeLocation;
}
/**
* @return the manager
*/
public String getManager() {
return manager;
}
/**
* @param manager the manager to set
*/
public void setManager(String manager) {
this.manager = manager;
}
}
解决方案
我能理解你的需求:你想根据表单下发的url动态生成查询条件。假设url映射到后端到一个HashMap<String,String>
.
例如,网址:
127.0.0.1/employees?nameContains=jack&ageEquals=10
地图:
HashMap<String, String>:key:nameContains,value:jack,key:ageEuqals,value:10
Spring 框架可以自动进行这种映射(RequestParamMapMethodArgumentResolver
)。您需要做的是通过此映射动态生成规范(规范)。
- 使用 reflect 获取字段对应的属性类型:name=>String, age=>Integer
- 使用 CriteriaBuilder 构建查询条件,具有完善的 api,例如:
谓词 like(Expression x, String pattern); => 包含
谓词等于(表达式 x,表达式 y);=> 相等
- 组装您的查询条件(或,和)
- 你得到一个规范。
这是一个比较复杂的解决思路,需要前表组件和后端的协调,但是会很方便。
我说的比较简单笼统,细节很多(比如嵌套属性,一对一,一对多等)
另外,你可以看看http://www.querydsl.com/
推荐阅读
- ruby-on-rails - 主动存储种子 Rails
- ios - 如何检查应用程序上次打开是多久以前
- c# - 在 .Net Core 2.0 + SQLite EFCore 中,并发检查不适用于“删除”
- java - 在 arrayList Java 中搜索对象
- maven - 使用 SpringBoot 构建 Gretty 失败
- python - 在python中使用groupby对数据进行分组
- php - 类、闭包和可调用对象
- java - File.listFiles() 方法有更好的替代方法吗?
- sql - 在sql中按升序排序文本变量,其中首先是拉丁字母,然后是西里尔字母
- c# - WPF 绑定命令到 Datagrid 组标题中的复选框