我正在开发一个Spring-MVC应用程序,我想在数据库中搜索一些提到的标准。不幸的是,它们大约有10-12个。所以我之前问过一个关于如何将它们分解成小块的问题,检查它们中的哪些不是空的,并将它们用作参数。通过使用如下所述的StringBuilder,我获得了部分成功。
我遇到的问题是如何为非空值设置query.setParameter(“variablename”,variableName)。首先是例子:
@Override
public List<Student> addHostSearchHistory(HostSearchHistory hostSearchHistory, Long hostId) {
session = this.sessionFactory.getCurrentSession();
Host host = (Host) session.get(Host.class,hostId);
host.getHostSearchHistorySet().add(hostSearchHistory);
hostSearchHistory.setHsHistory(host);
session.save(hostSearchHistory);
session.flush();
StringBuilder sb = new StringBuilder();
sb.append("from Student as s where ");
if(!(hostSearchHistory.getCountry().equals(""))){
sb.append("s.country=:").append(hostSearchHistory.getCountry());
}
if(!(hostSearchHistory.getCity().equals(""))){
sb.append("OR s.city=:").append(hostSearchHistory.getCity());
}
if(!(hostSearchHistory.getDrivingLicense().equals(""))){
sb.append("OR s.studentDetails.drivingLicense=").append(hostSearchHistory.getDrivingLicense());
}
if(!(hostSearchHistory.getGender().equals(""))){
sb.append("OR s.gender=").append(hostSearchHistory.getGender());
}
if(!(hostSearchHistory.getMotherTongue().equals(""))){
sb.append("OR s.studentDetails.motherTongue=:").append(hostSearchHistory.getMotherTongue());
}
if(!(hostSearchHistory.getSmoker().equals(""))){
sb.append("OR s.studentDetails.smoker=").append(hostSearchHistory.getSmoker());
}
if(!(hostSearchHistory.getPreviousAuPair().equals(""))){
sb.append("OR s.studentDetails.previouslyAuPair=").append(hostSearchHistory.getPreviousAuPair());
}
if(!(hostSearchHistory.getWillingToWork().equals(""))){
sb.append("OR s.studentDetails.willingToWork=").append(hostSearchHistory.getWillingToWork());
}
if(!(hostSearchHistory.getWorkForSingleParent().equals(""))){
sb.append("OR s.studentDetails.workForSingleParent=").append(hostSearchHistory.getWorkForSingleParent());
}
if(!(hostSearchHistory.getWorkingForDisabledChild().equals(""))){
sb.append("OR s.studentDetails.workingForDisabledChild").append(hostSearchHistory.getWorkingForDisabledChild());
}
sb.append(" order by s.registrationDate desc");
Query query = session.createQuery(sb.toString());
if(!(hostSearchHistory.getCountry().equals(""))){
query.setParameter("country",hostSearchHistory.getCountry());
}
if(!(hostSearchHistory.getCity().equals(""))){
query.setParameter("city",hostSearchHistory.getCity());
}
if(!(hostSearchHistory.getDrivingLicense().equals(""))){
query.setParameter("drivingLicense",hostSearchHistory.getDrivingLicense());
}
if(!(hostSearchHistory.getGender().equals(""))){
query.setParameter("gender",hostSearchHistory.getGender());
}
if(!(hostSearchHistory.getMotherTongue().equals(""))){
query.setParameter("motherTongue",hostSearchHistory.getMotherTongue());
}
if(!(hostSearchHistory.getSmoker().equals(""))){
query.setParameter("smoker",hostSearchHistory.getSmoker());
}
if(!(hostSearchHistory.getPreviousAuPair().equals(""))){
query.setParameter("previouslyAuPair",hostSearchHistory.getPreviousAuPair());
}
if(!(hostSearchHistory.getWillingToWork().equals(""))){
query.setParameter("willingToWork",hostSearchHistory.getWillingToWork());
}
if(!(hostSearchHistory.getWorkForSingleParent().equals(""))){
query.setParameter("workForSingleParent",hostSearchHistory.getWorkForSingleParent());
}
if(!(hostSearchHistory.getWorkingForDisabledChild().equals(""))){
query.setParameter("workingForDisabledChild",hostSearchHistory.getWorkingForDisabledChild());
}
List<Student> studentList = query.list();
for(Student student : studentList){
System.out.println("Student name is "+student.getUsername());
}
return studentList;
}
现在,即使我可以像这样构建查询,我还必须继续挖掘HostSearchHistory,然后设置query.setParameters()。还有其他选择吗?
另外,正如大家们可能已经注意到的那样,最后一个sb.append从映射请求信息,特别是与StudentInfo的一对一映射。这种语法是否正确?我发布了以下学生和学生信息模型,以进一步明确。请告诉我。非常感谢。
学生模特:
@Entity
@Table(name="student")
public class Student implements UserDetails{
@Id
@Column(name="studentid")
@GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "student_seq_gen")
@SequenceGenerator(name = "student_seq_gen",sequenceName = "student_seq")
private Long studentid;
@OneToOne(mappedBy = "studentDetails",fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
private StudentInfo studentInfoDetails = new StudentInfo();
public void setStudentInfoDetails(StudentInfo studentInfoDetails){
this.studentInfoDetails = studentInfoDetails;
}
public StudentInfo getStudentInfoDetails(){
return this.studentInfoDetails;
}
}
StudentInfo模型:
@Entity
@Table(name = "studentinfo")
public class StudentInfo {
@Id
@Column(name="infoid")
@GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "student_info_gen")
@SequenceGenerator(name = "student_info_gen",sequenceName = "student_info_seq")
private Long studentInfoId;
@OneToOne
@JoinColumn(name = "studentid",nullable = false)
private Student studentDetails;
public Student getStudentDetails() {
return studentDetails;
}
public void setStudentDetails(Student studentDetails) {
this.studentDetails = studentDetails;
}
}
感谢您的帮助。
答案 0 :(得分:1)
这是我项目中的一个示例,我不会建议更好的方法,但会在您的查询中显示一些遗漏点。我也有更长的查询,但写这个以保持简单。我使用 CreateQuery
方法:
@Override
public List<CampaignCode> queryCampaignCode(Merchant merchant, PaymentSystemType paymentSystemType, Date now) {
if (merchant == null) {
new IllegalArgumentException("Merchant parameter can not be null!");
}
StringBuilder sb = new StringBuilder();
sb.append("FROM ").append(CampaignCode.class.getName()).append(" WHERE merchant=:merchant");
if (paymentSystemType != null) {
sb.append("AND paymentSystemType=:paymentSystemType ");
}
if (now != null) {
sb.append(" AND :now BETWEEN startDate AND endDate ");
}
//Return current session
Query query = getSession().createQuery(sb.toString());
if (paymentSystemType != null) {
query.setParameter("paymentSystemType", paymentSystemType);
}
if (now != null) {
query.setParameter("now", now);
}
query.setParameter("merchant", merchant);
return query.list();
}
merchant
对象,它始终设置,所以我在创建sql的每个可能性中都没有语法错误。在您的示例中,如果用户仅设置国家/地区,则在运行时获得sql语法异常,非常谨慎地使用AND
。 String#equals
方法检查我总是信任Apache StringUtils#isBlank
如果我的所有参数都是字符串(我的样本不是这种情况,但在您的情况下我更喜欢StringUtils#isBlank
})Student.class.getName()
获取表名,这样您的查询就会知道您的类名是否已更改。<强> 最后 强>
我很满意这种用法,我也可以将这种方法用于上层的业务逻辑(服务或业务层)所以我用这种方式一次又一次地重复使用相同的方法。
<强> 修改 强>
编辑完成后,如果国家未设置且城市或其他参数为SET,则仍会发生我的第一个场景。
答案 1 :(得分:1)
我认为您可以使用Hibernate Query By Example简化这一过程。您只需将所有参数值设置为示例对象(null
值将被忽略,因此任何null
都不会包含在生成的SQL中。它看起来像这样
Student s = new Student();
s.setCountry(hostSearchHistory.getCountry());
s.setCity(hostSearchHistory.getCity());
...
StudentDetails sd = new StudentDetails();
sd.setDrivingLicense(hostSearchHistory.getDrivingLicense());
sd.setSmoker(hostSearchHistory.getSmoker());
...
Criteria crit = session.createCriteria(Student.class);
crit.add(Example.create(s));
crit.createCriteria("studentDetails").add(Example.create(sd));
List<Student> studentList = crit.list();
有一些限制,例如id
字段被忽略,关联也是如此(否则只需将sd
设置为s
即可。)