Primefaces LazyDataModel: правильный способ использования
У меня огромный список объектов, каждый из которых содержит количество изображений. Я хочу использовать ленивую загрузку, чтобы получить их частично. И я хочу понять, как использовать LazyDataModel и как это работает.
Изначально я думал, что мне нужно сохранять только идентификаторы потенциально извлеченных объектов внутри LazyDataModel. И когда вызывается метод load() - я должен получить изображения из БД и заменить источник данных извлеченными данными. Поэтому каждый раз, когда я хочу загрузить больше данных, я запускаю запрос.
private List<MyEntity> datasource; // contains only ids of MyEntity
@Override
public List<MyEntity> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String,Object> filters) {
//rowCount
int dataSize = datasource.size();
this.setRowCount(dataSize);
//get listOfIdToFetch
//paginate
datasource = datasource.addAll(myJpaRepository.findByIds(listOfIdToFetch));
return datasource;
}
Я не мог заставить это работать, потому что основные лица использовали метод lock() и выдавали исключение, когда новая часть данных должна была быть загружена:
org.springframework.webflow.conversation.impl.LockTimeoutException: невозможно получить блокировку разговора через 30 секунд
В конце концов, я понял, что пример простого языка LazyDataModel (где полный список данных, сохраненных в источнике данных, включая все изображения), может быть правильным способом использования. Потому что изначально я думал, что это упрощенный фиктивный пример, и в реальном проекте я буду использовать sql запросы для получения изображений по частям.
private List<MyEntity> datasource; // contains all images of all records
@Override
public List<MyEntity> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String,Object> filters) {
//rowCount
int dataSize = datasource.size();
this.setRowCount(dataSize);
//paginate
return datasource.subList(first, first + pageSize);
}
Я хочу понять, как LazyDataModel работает и увеличивает производительность. Если правильный способ использования этого подхода - извлечь все данные из БД и сохранить их в источнике данных. Сохраняет ли Primefaces эти данные на сервере и сбрасывает их по частям? Что если результат sql содержит тысячи изображений, следует ли мне искать другой подход и устанавливать лимит найденных записей? Как добиться лучшего увеличения производительности при отложенной загрузке? Или, возможно, первоначальный подход правильный, и я должен выяснить, почему возникает эта ошибка?
1 ответ
Хорошо, я наконец сделал это, и идея, что я должен выполнять запрос каждый раз при запуске метода load(), была правильной.
Проблемы, с которыми я сталкиваюсь:
- Если я просто возвращаю результат моего запроса, метод load() запускается только один раз, и я не могу загрузить больше данных. Поэтому я использую фиктивный подсписок (0, chunkSize).
- Я не смог @Autowire моего хранилища, у меня было исключение, сказав, что некоторые объекты не сериализованы. Но я мог бы использовать EntityManager, и это то, что я сделал.
Исходный код:
private List<MyEntity> datasource; // contains only ids
@Override
public List<MyEntity> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String,Object> filters) {
StringBuilder queryText = new StringBuilder("select ...");
List<MyEntity> list;
//paginate
if(datasource.size() > pageSize) {
try {
list = new ArrayList<>(datasource.subList(first, first + pageSize));
}
catch(IndexOutOfBoundsException e) {
list = new ArrayList<>(datasource.subList(first, first + (datasource.size() % pageSize)));
}
}
else {
list = new ArrayList<>(datasource);
}
boolean setComa = false;
for (MyEntity a: list) {
if (setComa) {
queryText.append(","+a.getId());
} else {
queryText.append(a.getId());
setComa = true;
}
}
queryText.append(")");
Query q = em.createQuery(queryText.toString());
list = q.getResultList();
return list.subList(0, list.size());
}
ОБНОВЛЕНИЕ ОГРАНИЧЕНИЯ:
@Override
public List<MyEntity> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String,Object> filters) {
List<MyEntity> list;
Query q = em.createQuery(this.queryText);
// Paginate
q.setFirstResult(first);
q.setMaxResults(pageSize);
list = query.getResultList();
return list.subList(0,list.size());
}