Reputation: 452
I have a huge list of objects, each of them contains number of images. I want to use lazy loading to fetch them partially. And I want to understand how to use LazyDataModel and how it works.
Initially I thought that I have to save only ids of potentially fetched objects inside LazyDataModel. And when load() method invoked - I have to fetch images from DB and replace datasource with fetched data. So every time I want to load more data, I run query.
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;
}
I couldn't make it work because primefaces used lock() method and throwed exception when new portion of data supposed to be loaded:
org.springframework.webflow.conversation.impl.LockTimeoutException: Unable to acquire conversation lock after 30 seconds
Finally I understood that primefaces example of LazyDataModel (where the full list of data saved to datasource, including all images), might be the correct way of using. Because initially I thought it is simplified dummy example and in real project I will use sql queries to fetch images part by part.
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);
}
I want to understand how LazyDataModel works and increases performance. If the correct way of using this approach is to retrieve all data from DB and save it to datasource. Does Primefaces keep this data on server and flushes part by part? What if sql result contains thousands of images, should I look for a different approach and set limit of retrieved records? How to achieve the best lazy loading performance increase? Or maybe the initial approach is correct and I should investigate why this error occurs?
Upvotes: 1
Views: 3028
Reputation: 452
Ok, I finally did it and the idea that I should execute query each time load() method is fired was correct.
Problems I faces:
Source code:
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());
}
UPDATE LIMITING:
@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());
}
Upvotes: -2