EclipseLink JPA: могу ли я выполнить несколько запросов от одного сборщика? - PullRequest
4 голосов
/ 03 сентября 2011

У меня есть метод, который создает и выполняет запрос Criteria. Запрос делает то, что я хочу, в частности, он фильтрует (и сортирует) записи на основе ввода пользователя.

Кроме того, размер запроса ограничен количеством записей на экране. Это важно, потому что таблица данных может быть очень большой.

Однако, если применяются фильтры, я хочу подсчитать количество записей, которые будут возвращены, если запрос не был ограничен. Таким образом, это означает выполнение двух запросов: один для извлечения записей, а затем один для подсчета записей, которые находятся в общем наборе. Это выглядит так:

public List<Log> runQuery(TableQueryParameters tqp) {

    // get the builder, query, and root

    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<Log> query = builder.createQuery(Log.class);
    Root<Log> root = query.from(Log.class); 

    // build the requested filters

    Predicate filter = null;
    for (TableQueryParameters.FilterTerm ft : tqp.getFilterTerms()) {

       // this section runs trough the user input and constructs the 
       // predicate

    }
    if (filter != null) query.where(filter);

    // attach the requested ordering

    List<Order> orders = new ArrayList<Order>();
    for (TableQueryParameters.SortTerm st : tqp.getActiveSortTerms()) {

        // this section constructs the Order objects

    }
    if (!orders.isEmpty()) query.orderBy(orders);        

    // run the query

    TypedQuery<Log> typedQuery = em.createQuery(query);
    typedQuery.setFirstResult((int) tqp.getStartRecord());
    typedQuery.setMaxResults(tqp.getPageSize());
    List<Log> list = typedQuery.getResultList();

    // if we need the result size, fetch it now

    if (tqp.isNeedResultSize()) {
        CriteriaQuery<Long> countQuery = builder.createQuery(Long.class);
        countQuery.select(builder.count(countQuery.from(Log.class)));
        if (filter != null) countQuery.where(filter);
        tqp.setResultSize(em.createQuery(countQuery).getSingleResult().intValue());
    }

    return list;
}

В результате я дважды вызываю createQuery для одного и того же CriteriaBuilder и делю объект Predicate (фильтр) между ними обоими. Когда я запускаю второй запрос, я иногда получаю следующее сообщение:

Исключение [EclipseLink-6089] (Eclipse Persistence Services - 2.2.0.v20110202-r8913): org.eclipse.persistence.exceptions.QueryException Exception Описание: выражение не было правильно инициализировано. Только один запрос ExpressionBuilder должен использоваться для запроса. Для параллельного выражений, класс запроса должен быть предоставлен ExpressionBuilder конструктор, и ExpressionBuilder запроса всегда должен быть на левая сторона выражения. Выражение: [База com.myqwip.database.Log] Запрос: ReportQuery (referenceClass = Log) в org.eclipse.persistence.exceptions.QueryException.noExpressionBuilderFound (QueryException.java:874) в org.eclipse.persistence.expressions.ExpressionBuilder.getDescriptor (ExpressionBuilder.java:195) в org.eclipse.persistence.internal.expressions.DataExpression.getMapping (DataExpression.java:214)

Может кто-нибудь сказать мне, почему эта ошибка появляется периодически, и что я должен сделать, чтобы это исправить?

Ответы [ 2 ]

3 голосов
/ 21 января 2012

Краткий ответ на вопрос: да, можно, но только последовательно.

В вышеописанном методе вы начинаете создавать первый запрос, затем начинаете создавать второй, выполняете второй, затем выполняете первый.

У меня была точно такая же проблема. Я не знаю, почему это непостоянно.

Другими словами, вы начинаете создавать свой первый запрос, и, прежде чем завершить его, вы начинаете создавать и выполнять другой.

Hibernate не жалуется, но eclipselink не нравится.

Если вы просто начнете с подсчета запросов, выполните его, а затем создадите и выполните другой запрос (что вы сделали, разделив его на 2 метода), eclipselink не будет жаловаться.

см. https://issues.jboss.org/browse/SEAMSECURITY-91

0 голосов
/ 06 сентября 2011

Похоже, что эта публикация не вызовет гораздо большего отклика, поэтому я отвечу на это в том, как я ее решил.

В конечном итоге я закончил ломать свою runQuery () метод на два метода: runQuery () , который выбирает записи, и runQueryCount () , который выбирает количество записей без параметров сортировки.Каждый метод имеет свой собственный вызов em.getCriteriaBuilder () .Я понятия не имею, какое влияние это оказывает на EntityManager, но проблема не возникает с тех пор.

Кроме того, объект DAO, который имеет эти методы, имел обыкновение быть @ApplicationScoped.Теперь у него нет объявленной области видимости, поэтому он создается по требованию от различных bean-компонентов @RequestScoped и @ConversationScoped, которые его используют.Я не знаю, имеет ли это какое-либо влияние на проблему, но так как оно не появилось, так как теперь я буду использовать его в качестве шаблона кода.Предложения приветствуются.

...