我正在开发软件,允许用户使用jpa / Criteria从数据库中动态选择一个或多个用户。
编辑/更新: - 我现在用ands增长谓词。问题是我没有指出正确的字段,而只是一个字符串,其中java正在查找用户输入的内容。 - 我仍然需要检查我如何使用pathes,因为我被建议做。
当用户输入d为PC_Name,d为姓名,c为Vorname时,详细的eclipselink会向我显示:
[EL Fine]: sql: 2012-07-25 15:44:13.173--ServerSession(24105143)--Connection(13480046)--Thread(Thread[main,5,main])--SELECT PERSONALNUMMER, GEBURTSTAG, GRUPPE, IP, MOBIL, NAME, PC_NAME, TELEFON, VORNAME FROM MITARBEITERTABELLE WHERE ((? LIKE ? AND ? LIKE ?) AND ? LIKE ?)
bind => [PC_Name, %d%, Name, %b%, Vorname, %c%]
这确认了我在说什么,当我输入n作为名称时,我得到整个数据库因为n总是属于名字..
编辑/更新结束
这是有效的sql版本:
try{
String selectString ="SELECT * FROM mitarbeitertabelle WHERE ";
selectString=StringModulierung(selectString);
PreparedStatement selectMitarbeiter = con.prepareStatement(selectString);
int i =1;
if(isNameSuche()){selectMitarbeiter.setString (i,this.wc+_Name+this.wc); i++;}
if(isVornameSuche()){ selectMitarbeiter.setString (i, this.wc+_Vorname+this.wc); i++;}
if(isPersonalnummerSuche()){selectMitarbeiter.setString (i, this.wc+_Personalnummer+this.wc); i++;}
if(isPC_NameSuche()){selectMitarbeiter.setString (i, this.wc+_PC_Name+this.wc); i++;}
if(isIPSuche()){selectMitarbeiter.setString (i, this.wc+_IP+this.wc); i++;}
if(isTelefonSuche()){ selectMitarbeiter.setString (i, this.wc+_Telefon+this.wc); i++;}
if(isGeburtstagSuche()){selectMitarbeiter.setString (i, this.wc+_Geburtstag+this.wc); i++;}
if(isGruppeSuche()){ selectMitarbeiter.setString (i, this.wc+_Gruppe+this.wc); i++;}
if(isMobilSuche()){ selectMitarbeiter.setString (i, this.wc+_Mobil+this.wc); i++;}
System.out.println(selectMitarbeiter.toString());
ResultSet ergebnis=selectMitarbeiter.executeQuery();`
使用:
public String StringModulierung(String str){
boolean erster=true;
if(isNameSuche()){ str=str.concat("Name LIKE ? ");
erster=false;
}
if(isVornameSuche()){ if(erster){str=str.concat("Vorname LIKE ? ");erster=false;
}else{str=str.concat("AND Vorname LIKE ? ");}
}
if(isPersonalnummerSuche()){ if(erster){str=str.concat("Personalnummer LIKE ? ");erster=false;
}else{str=str.concat("AND Personalnummer LIKE ? ");}
}
if(isPC_NameSuche()){ if(erster){str=str.concat("PC_Name LIKE ? ");erster=false;
}else{str=str.concat("AND PC_Name LIKE ? ");}
}
if(isIPSuche()){ if(erster){str=str.concat("IP LIKE ? ");erster=false;
}else{str=str.concat("AND IP LIKE ? ");}
}
if(isTelefonSuche()){ if(erster){str=str.concat("Telefon LIKE ? ");erster=false;
}else{str=str.concat("AND Telefon LIKE ? ");}
}
if(isGeburtstagSuche()){ if(erster){str=str.concat("Geburtstag LIKE ? ");erster=false;
}else{str=str.concat("AND Geburtstag LIKE ? ");}
}
if(isGruppeSuche()){ if(erster){str=str.concat("Gruppe LIKE ? ");erster=false;
}else{str=str.concat("AND Gruppe LIKE ? ");}
}
if(isMobilSuche()){ if(erster){str=str.concat("Mobil LIKE ? ");erster=false;
}else{str=str.concat("AND Mobil LIKE ? ");}
}
return str;
}
以下是我用jpa做的事情:
CriteriaBuilder cb = EM.getCriteriaBuilder();
CriteriaQuery<Mitarbeiter2> q = cb.createQuery(Mitarbeiter2.class);
Root<Mitarbeiter2> mit= q.from(Mitarbeiter2.class);
ParameterExpression<String> pc_name = cb.parameter(String.class,"PC_Name_p");
ParameterExpression<String> ip = cb.parameter(String.class,"IP_p");
ParameterExpression<String> pers_num = cb.parameter(String.class,"Personalnummer_p");
ParameterExpression<String> name = cb.parameter(String.class,"Name_p");
ParameterExpression<String> vorname = cb.parameter(String.class,"Vorname_p");
ParameterExpression<String> telefon = cb.parameter(String.class,"Telefon_p");
ParameterExpression<String> geburtstag = cb.parameter(String.class,"Geburtstag_p");
ParameterExpression<String> gruppe = cb.parameter(String.class,"Gruppe_p");
ParameterExpression<String> mobil = cb.parameter(String.class,"Mobil_p");
Predicate p = cb.conjunction();
if(isPC_NameSuche()){
p = cb.and(p, cb.like(pc_name, this.getWc()+_PC_Name+this.getWc() ));
}
if(isIPSuche()) {
p = cb.and(p, cb.like(ip,this.getWc()+_IP+this.getWc()));
}
if(isPersonalnummerSuche()) {
p = cb.and(p, cb.like(pers_num, this.getWc()+_Personalnummer+this.getWc() ));}
if(isNameSuche()){
p = cb.and(p, cb.like(name, this.getWc()+_Name+this.getWc()));
}
if(isVornameSuche()) {
p = cb.and(p, cb.like(vorname, this.getWc()+_Vorname+this.getWc()));}
if(isTelefonSuche()) {
p = cb.and(p, cb.like(telefon, this.getWc()+_Telefon+this.getWc() ));}
if(isGeburtstagSuche()){
p = cb.and(p, cb.like(geburtstag, this.getWc()+_Geburtstag+this.getWc()));}
if(isGruppeSuche()) {
p = cb.and(p, cb.like(gruppe, this.getWc()+_Gruppe+this.getWc()));}
if(isMobilSuche()) {
p = cb.and(p, cb.like(mobil, this.getWc()+_Mobil+this.getWc()));}
q.where(p);
q.select(mit);
TypedQuery<Mitarbeiter2> tq = EM.createQuery(q);
tq.setParameter("PC_Name_p", "PC_Name"); // searches this.getWc()+_Mobil+this.getWc() in PC_Name !
tq.setParameter("IP_p", "IP");
tq.setParameter("Personalnummer_p", "Personalnummer");
tq.setParameter( name/**entered by user*/, "Name"/**should be the field */);
tq.setParameter("Vorname_p", "Vorname");
tq.setParameter("Telefon_p", "Telefon");
tq.setParameter("Geburtstag_p","Geburtstag" );
tq.setParameter("Gruppe_p", "Gruppe");
tq.setParameter("Mobil_p" ,"Mobil");
List<Mitarbeiter2> ergebnis= tq.getResultList();
我已经纳入了以下两个解决方案:
为了在条件中动态添加,您可以使用 列出每个Predicate的定义如下:
> Predicate p = cb.like(...);
或者您可以像这样动态修改单个谓词:
> Predicate p = cb.conjunction(); for ( filter : filters) {
> p = cb.and(p, cb.like(...)); }
和
当您执行q.where设置WHERE表达式时。
它没有追加,意思是,你调用的最后一个q是那个 为查询设置。
你需要做的是构建一个布尔表达式(我认为ANDs是 你想要的是什么。
然后在和用户q.where设置表达式。
感谢您的帮助;)。
哈拉尔德
答案 0 :(得分:1)
我遇到的两个问题是: 1)如何使用Criteria动态构建查询,以获得像(在SQL中)这样的查询(具有许多不同的谓词)?
SELECT * FROM mitarbeitertabelle where (1) like (2) and (3) like (4)
...
这意味着在运行时,用户可以选择一个或多个标准,用于搜索mitarbeiter(德语为员工)。
2)如何设置指向对象属性的链接?
1)为了做到这一点,你必须使用谓词来构建谓词,如果选择了标准,则每次添加新谓词时都会修改谓词。
p= criteriabuilder.and(p, criteriabuilder.like(path object linking to the right attribute, String s used for the search));
2)正确的路径使我们能够拥有指向正确属性的链接。我在上面使用它。在这里,事情就是没有路径,到目前为止,我知道不可能有你的属性的链接;)。
之后,你只需要通过添加where子句来实现你的sql命令,where子句将谓词作为参数,select子句以root(我们将在数据库中搜索)作为参数:
q.where(p);
q.select(mit);
然后,得到你的结果:
List<Mitarbeiter2> ergebnis= EM.createQuery(q).getResultList();
这不需要填充和使用参数化表达式对象,因为我没有使用参数化表达式对象。用于搜索的字符串在运行时执行时直接在like子句中设置。
整个代码(包含我的变量,名称,......)是:
CriteriaBuilder cb = EM.getCriteriaBuilder();
CriteriaQuery<Mitarbeiter2> q = cb.createQuery(Mitarbeiter2.class);
Root<Mitarbeiter2> mit= q.from(Mitarbeiter2.class);
Path<String> pc_name2 = mit.get("PC_Name");
Path<String> ip2 = mit.get("IP");
Path<String> pers_num2 = mit.get("Personalnummer");
Path<String> name2 = mit.get("Name");
Path<String> vorname2 = mit.get("Vorname");
Path<String> telefon2 = mit.get("Telefon");
Path<String> geburtstag2 = mit.get("Geburtstag");
Path<String> gruppe2 = mit.get("Gruppe");
Path<String> mobil2 = mit.get("Mobil");
Predicate p = cb.conjunction();
if(isPC_NameSuche()){
p = cb.and(p, cb.like(pc_name2, this.getWc()+_PC_Name+this.getWc() ));
}
if(isIPSuche()) {
p = cb.and(p, cb.like(ip2,this.getWc()+_IP+this.getWc()));
}
if(isPersonalnummerSuche()) {
p = cb.and(p, cb.like(pers_num2, this.getWc()+_Personalnummer+this.getWc() ));}
if(isNameSuche()){
p = cb.and(p, cb.like(name2, this.getWc()+_Name+this.getWc()));
}
if(isVornameSuche()) {
p = cb.and(p, cb.like(vorname2, this.getWc()+_Vorname+this.getWc()));}
if(isTelefonSuche()) {
p = cb.and(p, cb.like(telefon2, this.getWc()+_Telefon+this.getWc() ));}
if(isGeburtstagSuche()){
p = cb.and(p, cb.like(geburtstag2, this.getWc()+_Geburtstag+this.getWc()));}
if(isGruppeSuche()) {
p = cb.and(p, cb.like(gruppe2, this.getWc()+_Gruppe+this.getWc()));}
if(isMobilSuche()) {
p = cb.and(p, cb.like(mobil2, this.getWc()+_Mobil+this.getWc()));}
q.where(p);
q.select(mit);
List<Mitarbeiter2> ergebnis= EM.createQuery(q).getResultList();
非常感谢你的帮助@perissf和@ aviram-segal!如果您认为在我的回答中不容易理解某些内容,请不要犹豫。
答案 1 :(得分:0)
当您执行q.where设置WHERE表达式时。
它没有追加,意思是,你调用的最后一个q是为查询设置的那个。
你需要做的是建立一个布尔表达式(我认为ANDs就是你想要的)。
然后在和用户q.where设置表达式。
答案 2 :(得分:0)
在equal
子句中,您使用的是以下表达式:
ParameterExpression<String> pc_name = cb.parameter(String.class,"PC_Name");
请改为使用:
Path<Mitarbeiter2> pc_name = mit.get("PC_Name");
或者,使用Metamodel生成的类,
Path<Mitarbeiter2> pc_name = mit.get(Mitarbeiter2_.pc_name);
我现在无法测试Path
表达式,但我确信以下方法有效:
q.where(cb.like(mit.get("PC_Name"), pc_name));
或:
q.where(cb.like(mit.get(Mitarbeiter2_.pc_name), pc_name));
为了添加动态where
条件,您可以使用List<Predicate>
,其中每个Predicate的定义如下:
Predicate p = cb.like(...);
或者您可以像这样动态修改单个Predicate
:
Predicate p = cb.conjunction();
for ( filter : filters) {
p = cb.and(p, cb.like(...));
}
最后,如果您要比较字符串,请不要忘记在进行比较之前将所有内容转换为相同的情况。