Anton Petrovskyi
Anton Petrovskyi

Reputation: 452

Primefaces LazyDataModel: (Outdated)

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

Answers (1)

Anton Petrovskyi
Anton Petrovskyi

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:

  1. If I return simply the result of my query - load() method is fired only once, and I can't load more data. So i use dummy sublist(0, chunkSize).
  2. I couldn't @Autowire my repository, I had an exception saying some objects are not Serialized. But I could use EntityManager and that's what I did.

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

Related Questions