JPA-итерация над полем сбора - PullRequest
3 голосов
/ 21 января 2012

Скажем, есть класс сущностей, подобный этому

@Entity
public class User {
...
public Collection<User> followers;
...
}

Допустим, у пользователя тысячи подписчиков. Я хочу разбить на страницы ... Нужно ли мне заводить руки в JPQL, чтобы разбить результат без какого-либо другого выбора?

int page = 5;
User u = em.find(User.class, id);

for (User u : u.getFollowers(page, 100)) { // get the 5th 100 result
// do some stuff
}

Есть ли подобное решение или шаблон? Возможно ли разбить на страницы поле времени выполнения коллекции, просто открыв поле u.getFollowers(page, 100) без кода ниже?

Я уже знаю это ...

int page = 5;
List<User> followers = em.createQuery("select u.followers from User u where u.id=?1", User.class)
.setParameter(1, id).setFirstResult(page*100).setMaxResult(100).getResultList();

Ответы [ 6 ]

2 голосов
/ 30 января 2012

какую реализацию JPA вы используете? если вы используете hibernate, вы можете воспользоваться некоторыми функциями hibernates.

как указано в документации на спящий режим

Метод createFilter() может использоваться для эффективного извлечения подмножеств коллекции без необходимости инициализации всей коллекции.

 List<User> followerPage = session.createFilter( followers, "")
                                  .setFirstResult(500).setMaxResults(100)
                                  .list(); 

Вы можете использовать createFilter(), чтобы получить размер коллекции без инициализации, что также важно для разбиения на страницы.

 ( (Integer) session.createFilter( followers, "select count(*)" ).list().get(0) ).intValue()
1 голос
/ 30 января 2012

У вас есть два варианта:

  1. Используйте JPA Query с setFirstResult()/setMaxResult()
  2. Получите List и извлеките subList, что вам нужно.

Вариант 1 является наиболее совместимым, чистым и рекомендуемым решением.

Вариант 2 может быть проблемой производительности (и даже памяти) -или нет.
Это зависит от того, сколько строк может быть прочитано в худшем случае и какое соотношение строк обычно читается. Если число строк мало или вы в большинстве случаев читаете весь список в любом случае - тогда пойдите для этого.
Там может также быть некоторой реализацией JPA, которая действительно выбираеттолько запрошенные записи списка лениво в некоторых случаях, но будьте осторожны и внимательно изучите документацию вашей реализации JPA.(Но я не в курсе таких реализаций)

1 голос
/ 26 января 2012

Отправленный вами JPQL-запрос имеет единственную проблему - не указан оператор ORDER BY. Важно использовать ORDER BY, так как для каждой страницы будет использоваться несколько запросов, и вы хотите гарантировать, что вы получите результаты в том же порядке.

Что касается вашего комментария о предполагаемой неэффективности получения всех строк и последующего извлечения подсписка этого: хорошо, провайдер JPA создаст за кулисами полный запрос, включая оператор LIMIT, когда JDBC-коннектор поддерживает его. Таким образом, вам не нужно заботиться об этом.

Если вы хотите убедиться в том, какой запрос эффективно отправляется на соединитель JDBC, установите для уровня ведения журнала поставщика JPA значение FINE и проверьте его.

Для получения дополнительной информации, если вы используете провайдера EclipseLink, просмотрите эту ссылку .

1 голос
/ 25 января 2012

Чтобы ответить на ваши вопросы:

Нужно ли мне заводить руки в JPQL, чтобы разбить результат без другого выбора?

Это будет зависеть от того, какхотел бы использовать восстановленные данные.в принципе, было бы лучше, если бы в запросе была сделана нумерация страниц, чтобы получить именно те строки, которые вам нужны, вместо того, чтобы получать все доступные строки, а затем вручную выполнять подсписок.шаблон там?Можно ли разбить на страницы поле времени выполнения коллекции, просто открыв поле u.getFollowers (стр. 100) без кода ниже

, если вы хотите выполнить разбиение на страницы после получения всех «последователей»затем просто используйте конструктор ArrayList, который принимает коллекцию в качестве параметра, а затем получите подсписок.

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

Да, вы должны выполнить запрос, чтобы иметь возможность разбивать на страницы.

Хороший фрагмент в последнем примере, за исключением разбивки на страницы без использования какого-либо порядка для сортировки результатов запроса, не является хорошей идеей: нет никакой гарантии детерминированного порядка результатов, если вы его не используете order by оговорка, AFAIK.

0 голосов
/ 30 января 2012

Существует один подход или шаблон, если вы хотите назвать его так, описанный в книге Адама Бина Реальный мир Java EE Patterns Rethinking Best Practices , называемый Paginator.

Одна стратегия реализации основана на запросе JPA с использованием уже упомянутого подхода Query (первый и максимальный результат). Следующий пример находится за пределами страницы 125:

@Stateful
public class CustomerQueryBean implements Iterator<List<Customer>> {

@PersistenceContext
private EntityManager em;
private int index = 0;
private int pageSize = 10;
private boolean next = true;

public void setPageSize(int pageSize){
    this.pageSize = pageSize;
}

public List<Customer> next(){
    List<Customer> retVal = null;
    Query query = this.em.createNamedQuery(Customer.ALL);
    query.setFirstResult(getFirst());
    query.setMaxResults(pageSize);
    retVal = query.getResultList();

    if(retVal.size()==0){
        this.next = false;
    }
    index++;
    return retVal;
}
private int getFirst(){
    return index * pageSize;
}
public boolean hasNext() {
    return this.next;
}
public void remove() {
    throw new UnsupportedOperationException("Operation remove …");
}
@Remove
public void close(){
    this.em.clear();
    this.em.close();
}
}

Как видите, подход основан на интерфейсе Iterator. Причина этого в том, что клиент все равно интересуется логикой итерации. После выполнения метода next () вы получаете новое подмножество сущностей.

Надеюсь, это поможет внести некоторую структуру в вашу логику нумерации страниц.

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