2012-07-24 165 views
0

我正在开发允许用户使用jpa/Criteria从数据库动态选择一个或多个用户的软件。从几个条件中选择jpa

编辑/更新: - 我现在使用ands增长的谓词。问题是我没有指出正确的字段,而只是一个字符串,其中java正在寻找用户输入的内容。 - 我仍然必须检查如何按照我的建议去做。

当用户输入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的名字,我获取整个数据库,因为ñ总是属于命名..

末的编辑/更新

这里是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(); 

我结合这两个以下解决方案:

为了动态添加where条件,您可以使用一个 列表,其中每个谓词定义如下:

> Predicate p = cb.like(...); 

,也可以动态修改单个预测是这样的:

> Predicate p = cb.conjunction(); for (filter : filters) { 
    >  p = cb.and(p, cb.like(...)); } 

当你q.where您设置的WHERE表达。

它不会追加,意思是说,您调用的最后一个q.是为查询设置的那个 。

你需要做的是建立一个布尔表达式(我认为ANDs是 你想要的)。

然后在和用户q.where设置表达式。

感谢您的帮助;)。

Harald

+0

您在哪里设置您定义的参数的值? – 2012-07-24 11:35:29

+0

Ups,我忘记了。现在我设置了参数,我没有抛出异常,但是如果我在字段中什么也不写,并选择它(isField())是真的,那么我得到我的整个数据库,否则我什么也得不到。我假设我没有正确使用通配符,并且它不被识别。 Mayne有一个更好的方法来使用标准来修改这个动态sql代码。我编辑我的代码。 – user1548451 2012-07-25 08:26:24

+0

如果您多次更改问题的内容,我们如何帮助您?现在我看到你已经实现了我的答案的一半,甚至没有引用它,并且你没有实现另一部分,没有解释原因。 – perissf 2012-07-25 14:49:39

回答

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子句和将根(我们将在数据库中搜索的位置)作为参数的select子句来实现sql命令:

q.where(p); 
    q.select(mit); 

然后,让你的结果:

List<Mitarbeiter2> ergebnis= EM.createQuery(q).getResultList(); 

Theere无需填写和使用parameterexpression对象,因为我没有使用parameterexpression对象。用于搜索的字符串在运行时执行时直接设置在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 - 西格尔!如果你认为在我的回答中有些东西不容易理解,请不要犹豫,评论。

0

当你做q.where你设置WHERE表达式。

它不会追加,意思是说,您调用的最后一个q.是为查询设置的。

你需要做的是建立一个布尔表达式(我认为ANDs是你想要的)。

然后在和用户q.where设置表达式。

0

在你equal条款,您使用这个表达式:

ParameterExpression<String> pc_name = cb.parameter(String.class,"PC_Name"); 

尝试,而不是这样的:

Path<Mitarbeiter2> pc_name = mit.get("PC_Name"); 

或者,使用元模型生成的类,

Path<Mitarbeiter2> pc_name = mit.get(Mitarbeiter2_.pc_name); 

我无法测试现在的Path表达式,但我确信t他以下的工作:

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 p = cb.like(...); 

或您可以像这样动态修改一个Predicate

Predicate p = cb.conjunction(); 
for (filter : filters) { 
    p = cb.and(p, cb.like(...)); 
} 

最后,如果您要比较字符串,不要忘记在做比较之前将所有内容都转换为相同的大小写。