2011-01-25 6 views
6

Mam ten sam problem, używając hibernacji przeciwko DB2 i MySQL.JPA2 zapytanie wyrażenia critera w przypadku problemów FK n wyrażeń select, gdzie n to #wartość

Tutaj jest test:

 EntityManager em = emf.createEntityManager(); 
     CriteriaBuilder cb = em.getCriteriaBuilder(); 
     CriteriaQuery<Customers> query = cb.createQuery(Customers.class); 
     Root<Customers> root = query.from(Customers.class); 

     ArrayList<String> strList = new ArrayList<String>(); 
     strList.add("ADMIN"); 
     strList.add("SYSADMIN"); 
     strList.add("SALES"); 

     ArrayList<Predicate> predicateList = new ArrayList<Predicate>(); 

     Path<Groups> groups = root.get(Customers_.groups); 
     Path<String> groupName = groups.get(Groups_.name); 
     In<String> in = cb.in(groupName); 
     for (String s : strList) { //has a value 
      in = in.value(s); 
     } 
     predicateList.add(in); 
     Predicate[] predicates = new Predicate[predicateList.size()]; 

     query.where(predicateList.toArray(predicates)); 
     TypedQuery<Customers> typedQuery = em.createQuery(query); 
     this.outList = typedQuery.getResultList(); 

Generuje zapytania I muszą następnie przez trzy niepotrzebnych zapytań (dodatkowy jeden tak wiele wartości są w strList). W dzienniku drukowane są następujące dane (sformułowałem pierwsze zapytanie, aby je rozdzielić.) Pierwsze zapytanie robi dokładnie to, czego chcę, to kolejne trzy zapytania, które w procesie produkcyjnym powodują niepotrzebne IO, z którym robię wyjątek. Uwaga: ten problem nie występuje, jeśli wyrażenie w wyrażeniu nie znajduje się na FK.

INFO: Hibernate: 
select 
    customers0_.id as id0_, customers0_.fname as fname0_, customers0_.groups as groups0_, customers0_.lname as lname0_ 
from 
    test.customers customers0_ 
where 
    customers0_.groups in (? , ? , ?) 

INFO: Hibernate: select groups0_.name as name1_0_ from test.groups groups0_ where groups0_.name=? 
INFO: Hibernate: select groups0_.name as name1_0_ from test.groups groups0_ where groups0_.name=? 
INFO: Hibernate: select groups0_.name as name1_0_ from test.groups groups0_ where groups0_.name=? 

Dlaczego dodatkowe trzy pytania? Jak im zapobiegać? Potrzebuję odpowiedzi jako Kryteria Zapytania.


Oto podmiot obiektów:

@Entity 
@Table(name = "customers", catalog = "test", schema = "") 
public class Customers implements Serializable { 
    private static final long serialVersionUID = 1L; 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Basic(optional = false) 
    @Column(name = "id", nullable = false) 
    private Integer id; 
    @Column(name = "fname", length = 45) 
    private String fname; 
    @Column(name = "lname", length = 45) 
    private String lname; 
    @JoinColumn(name = "groups", referencedColumnName = "name") 
    @ManyToOne 
    private Groups groups; 

...getters and setters... 
} 

Następny jednostka

@Entity 
@Table(name = "groups", catalog = "test", schema = "") 
public class Groups implements Serializable { 
    private static final long serialVersionUID = 1L; 
    @Id 
    @Basic(optional = false) 
    @Column(name = "name", nullable = false, length = 45, unique = true) 
    private String name; 
    @OneToMany(mappedBy = "groups") 
    private Collection<Customers> customersCollection; 

...getters and setters... 
} 

Edit ~~~~~~~~~~~~~~~~~ ~~~~~~~~ ROZWIĄZANIE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~:

Dodawanie druga linia do Powyższy kod rozwiązuje problem (dziękuję Clement):

Root<Customers> root = query.from(Customers.class); 
root.fetch(Customers_.groups, JoinType.LEFT); //that's it that's all now it will not create the extra queries 
+0

Czy spojrzał czy JPQL by Ci pomóc? http://stackoverflow.com/questions/2687690/jpa-2-and-hibernate-3-5-1-member-of-query-doesnt-work –

+0

Używanie MySQL lub DB2 nie jest częścią problemu. W jakiś sposób JPA myśli, że prosiłeś o wartości na liście projekcji, a nie "IN (v1, v2, v3)". –

+0

@James: To tylko niewielka część znacznie większego zapytania, które zawiera wiele możliwych kryteriów, więc wolę trzymać się kryteriów. – Quaternion

Odpowiedz

2

Przyczyną dodatkowego zapytania Wynika to z faktu, że używasz pola: private Groups groups; dla Stowarzyszenia od klientów do grup. Ponieważ hibernacja nie może przechwycić bezpośredniego dostępu do pola, musi pobrać obiekt Grupy podczas pobierania klienta. Robi to w przypadku zapytań kryterialnych w trybie wyboru N + 1 (zamiast, na przykład, wymyślać, że robi się automatycznie i wybiera podselek).

Aby rozwiązać ten problem, można powiedzieć hibernacji sprowadzić stowarzyszenie, a także:

root.fetch(Customers_.groups, JoinType.LEFT); // LEFT join since your schema could have a customer with a null group. 
+0

Uprzejmie proszę o nagrodę. Dzięki. –

+0

Czy wiesz, że nie możesz przyznać nagrody do 5h po zaakceptowaniu (a tak się wydaje ... pierwszy zaoferowałem, więc nie wiedziałem, że to jeszcze 2 godziny!). – Quaternion

+0

ic, moje złe, też tego nie wiedziałem. :) –