Выражение запроса критерия JPA2 на FK выдает n операторов select, где n равно #values - PullRequest
6 голосов
/ 26 января 2011

У меня такая же проблема при использовании hibernate против DB2 и MySQL.

Вот тест:

        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();

Создает запрос, который мне нужен, за которым следуют три ненужных запроса (дополнительный для такого количества значений в strList). Следующее напечатано в журнале (я отформатировал первый запрос, чтобы выделить его). Первый запрос делает именно то, что я хочу, это следующие три запроса, которые в производственном процессе вызывают ненужный ввод-вывод, с которым я беру исключение. Обратите внимание, что эта проблема не возникает, если в выражении отсутствует на 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=?

Почему три лишних запроса? Как мне их предотвратить? Мне нужен ответ как критерий запроса.


Вот объекты сущности:

@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... 
}

Следующая сущность

@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... 
}

Редактировать ~~~~~~~~~~~~~~~~~~~~~~~~~ SOLUTION ~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~:

Добавление второй строки к приведенному выше коду решает проблему (спасибо, Клемент):

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

1 Ответ

2 голосов
/ 28 января 2011

Причиной дополнительного запроса является тот факт, что вы используете поле: private Groups groups; для связи между клиентами и группами. Поскольку hibernate не может перехватить прямой доступ к полям, он должен извлекать объект Groups, когда вы выбираете Customer. Это делается для запросов критериев способом выбора N + 1 (вместо того, чтобы, например, выяснить это и выполнить объединение автоматически или подвыбор).

Чтобы это исправить, вы также можете указать hibernate для получения ассоциации:

root.fetch(Customers_.groups, JoinType.LEFT); // LEFT join since your schema could have a customer with a null group.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...