Home » Java » Enterprise Java » Primefaces DataTable Lazy Loading with pagination, filtering and sorting using JPA Criteria, @ViewScoped

About Leonardo Shikida

Leonardo Shikida

Leonardo is a Systems Analyst and Java Senior Developer at IBM (The postings on his site are his own and don’t necessarily represent IBM’s positions, strategies or opinions.)

Primefaces DataTable Lazy Loading with pagination, filtering and sorting using JPA Criteria, @ViewScoped

Primefaces datatable lazy pagination works, but I was really frustrated after searching for a full example using Criteria in the web. So I’ve mixed solutions from

  • http://stackoverflow.com/questions/13972193/how-to-query-data-for-primefaces-datatable-with-lazy-loading-and-pagination
  • http://www.primefaces.org/showcase/ui/datatableLazy.jsf
  • http://www.javacodegeeks.com/2012/04/lazy-jsf-primefaces-datatable.html

To put all together in a complete example using:
 
 

  • Primefaces 4.0
  • TomEE 1.6.0+
  • Criteria JPA

With:

  • Filtering
  • Sorting
  • Pagination
  • Using @ViewScoped Managed Beans

So let’s go:

xhtml snippet

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:p="http://primefaces.org/ui">
<h:body>
    <h:form id="am">

            <p:dataTable
                var="element"
                value="#{inventoryManagerMB.model}"
                lazy="true"
                paginator="true"
                rows="10"
                paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
                rowsPerPageTemplate="10,50,100"
                id="sites">
 
            <p:column sortBy="id" filterBy="id" filterMatchMode="contains" headerText="ID">                
                <h:outputText value="#{element.id}" />
            </p:column>
            <p:column sortBy="name" filterBy="name" filterMatchMode="contains" headerText="Name">                
                <h:outputText value="#{element.name}" />
            </p:column>
            <p:column sortBy="siteType.name" filterBy="siteType.name" filterMatchMode="contains" headerText="Type">                
                <h:outputText value="#{element.siteType.name}" />
            </p:column>
            <p:column sortBy="ip" filterBy="ip" filterMatchMode="contains" headerText="IP">                
                <h:outputText value="#{element.ip} " />
            </p:column>
            <p:column sortBy="description" filterBy="description" filterMatchMode="contains" headerText="Description">                
                <h:outputText value="#{element.description}" />
            </p:column>
            </p:dataTable>
    </h:form>
</h:body>
</html>

ManagedBean

@ManagedBean
@ViewScoped
public class InventoryManagerMB implements Serializable {

    private static final long serialVersionUID = -1201944101993687165L;

    @EJB
    private InventoryManagerEJB inventoryManagerEJB;
   
    private LazyDataModel<Site> model;
 


     @PostConstruct
    public void init() {
        try {
            this.model = new LazyDataModel<Site>(){
                private static final long    serialVersionUID    = 1L;
                @Override
                public List<Site> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters) {
                    List<Site> result = inventoryManagerEJB.getResultList(first, pageSize, sortField, sortOrder, filters);
                    model.setRowCount(inventoryManagerEJB.count(sortField, sortOrder, filters));
                    return result;
                }
            };
}

    public LazyDataModel<Site> getModel() {
        return model;
    }

    public void setModel(LazyDataModel<Site> model) {
        this.model = model;
    }
 
(...)

EJB

@Stateless
public class InventoryManagerEJB {
   
    @Inject
    private BaseService baseService;

    public List<Site> getResultList(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters) {
        List<Site> all = new ArrayList<Site>();
        all.addAll(this.baseService.getSiteDAO().getAll(first,pageSize,sortField,sortOrder,filters));
        return all;
    }

    public int count(String sortField, SortOrder sortOrder, Map<String, String> filters) {
        return this.baseService.getSiteDAO().getAll(-1,-1,null,null,filters).size();
    }
}

BaseService

@ApplicationScoped
public class BaseService implements Serializable{
   
    private static Logger log = Logger.getLogger(BaseService.class);
   
    /*
     * persistence
     */
   
    private static final long serialVersionUID = 588696475267901772L;

    @PersistenceContext
    private EntityManager entityManager;

    private SiteDAO siteDAO;

    @PostConstruct
    public void init() {
            siteDAO = new SiteDAO(entityManager);
    }


    public SiteDAO getSiteDAO() {
        return siteDAO;
    }

SiteDAO

public class SiteDAO extends GenericDAO<Site>{

    public SiteDAO(EntityManager entityManager) {
        super(entityManager);
    }

    public Collection<Site> getAll(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<Site> q = cb.createQuery(Site.class);
        Root<Site> site = q.from(Site.class);
        Join<Site,SiteType> siteType = site.join(Site_.siteType);
        q.select(site);


        Path<?> path = getPath(sortField, site, siteType);
        if (sortOrder == null){
            //just don't sort
        }else if (sortOrder.equals(SortOrder.ASCENDING)){
            q.orderBy(cb.asc(path));
        }else if (sortOrder.equals(SortOrder.DESCENDING)){
            q.orderBy(cb.asc(path));
        }else if (sortOrder.equals(SortOrder.UNSORTED)){
            //just don't sort
        }else{
            //just don't sort
        }
       
        //filter
        Predicate filterCondition = cb.conjunction();
        for (Map.Entry<String, String> filter : filters.entrySet()) {
            if (!filter.getValue().equals("")) {
                //try as string using like
                Path<String> pathFilter = getStringPath(filter.getKey(), site, siteType);
                if (pathFilter != null){
                    filterCondition = cb.and(filterCondition, cb.like(pathFilter, "%"+filter.getValue()+"%"));
                }else{
                    //try as non-string using equal
                    Path<?> pathFilterNonString = getPath(filter.getKey(), site, siteType);
                    filterCondition = cb.and(filterCondition, cb.equal(pathFilterNonString, filter.getValue()));
                }
            }
        }
        q.where(filterCondition);
       
        //pagination
        TypedQuery<Site> tq = entityManager.createQuery(q);
        if (pageSize >= 0){
            tq.setMaxResults(pageSize);
        }
        if (first >= 0){
            tq.setFirstResult(first);
        }
        return tq.getResultList();
    }

    private Path<?> getPath(String field, Root<Site> site, Join<Site, SiteType> siteType) {
        //sort
        Path<?> path = null;
        if (field == null){
            path = site.get(Site_.name);
        }else{
            switch(field){
                case "id":
                    path = site.get(Site_.id);
                    break;
                case "name":
                    path = site.get(Site_.name);
                    break;
                case "siteType.name":
                    path = siteType.get(SiteType_.name);
                    break;
                case "ip":
                    path = site.get(Site_.ip);
                    break;
                case "description":
                    path = site.get(Site_.description);
                    break;
            }
        }
        return path;
    }

    private Path<String> getStringPath(String field, Root<Site> site, Join<Site, SiteType> siteType) {
        //sort
        Path<String> path = null;
        if (field == null){
            path = site.get(Site_.name);
        }else{
            switch(field){
                case "id":
                    path = null;
                    break;
                case "name":
                    path = site.get(Site_.name);
                    break;
                case "siteType.name":
                    path = siteType.get(SiteType_.name);
                    break;
                case "ip":
                    path = site.get(Site_.ip);
                    break;
                case "description":
                    path = site.get(Site_.description);
                    break;
            }
        }
        return path;
    }
}

Entity

@Entity
@Table([email protected](columnNames={"name"}))
public class Site implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 8008732613898597654L;
   
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
   
    @Nameable
    @Column(nullable=false)
    private String name;
   
    private String ip;   
   
    private String description;
   
    @ManyToOne
    @JoinColumn(name="siteTypeId")
    private SiteType siteType;

(...)
}

That’s it. Enjoy.
 

Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
Email address:

Leave a Reply

25 Comments on "Primefaces DataTable Lazy Loading with pagination, filtering and sorting using JPA Criteria, @ViewScoped"

Notify of
avatar
Sort by:   newest | oldest | most voted
MarceL
Guest

Hi. Can you, please, post the the full project for download? I really appreciate that! Thanks. and congratulations for your work!

Leonardo Shikida
Guest

Hi Marcel. Right now, I can’t publish the full project due to legal reasons. Sorry.

MarceL
Guest

Ok, I understand that. I’ll try to build it. Thanks for answering.

Alex
Guest

Hi, I would like to know the code of the “GenericDAO” -class. Can you post it please?

Leonardo Shikida
Guest
Tet
Guest

hello, i use oracle db and i have blob field containing an image in the database. i would like to load a photo in xhtml file using EntityManager, for db connection (without DAO) , can you publish such example, thanks in advance

Leonardo Shikida
Guest
You may find this stackoverflow thread useful – http://stackoverflow.com/questions/8304967/how-to-use-pgraphicimage-with-streamedcontent-within-pdatatable But basically, it seems there are at least two things about p:graphicimage that you must know (I don’t know why primefaces oficial documentation and demo doesn’t say a word about this but anyway) [1] your image is not available during the RENDER_RESPONSE phase [2] @ViewScoped won’t work So here’s the code that worked for me [1] Managed bean is session scoped and the bean attribute is not DefaultStreamedContent (which is not serializable) but byte[]. @ManagedBean @SessionScoped public class ImageController implements Serializable{ private byte[] img; [2] the dynamic image getter method is… Read more »
Felix
Guest

Works great! But I don’t like the count implementation. That means, that you select all filtered values from the database just to execute “.size()” on the result list. Wouldn’t it be better to use a SQL query to do that? Like:
“SELECT COUNT(s) FROM Site s” and then add the creterias?

Leonardo Shikida
Guest

you’re right.

a much better approach for the count() method is to duplicate the query method in the DAO, changing the return result to a Long (although, primefaces will expect an Integer) like this — CriteriaQuery q = cb.createQuery(Long.class); , removing the pagination code (setMaxResults and setFirstResult) and returning just the count like this — return entityManager.createQuery(q).getSingleResult(); — thanks!

Leonardo Shikida
Guest

you’re right. A SQL just for count would be better in this case.

Sanjay
Guest

What is this SiteType_.name and where you have defined this?

Leonardo Shikida
Guest

This class is a Criteria metamodel class, generated during compilation. Check this link for instructions on how to generate them manually — http://openjpa.apache.org/builds/2.1.1/apache-openjpa/docs/ch13s04.html — or this link to configure eclipse to do it automatically for you — http://www.javabeat.net/jpa-2-metamodel-eclipse/

Sanjay
Guest

I have the similar issue where I have to join multiple sub object to the main query like Subscription–> Customer, SubscriptionMode, Payment Type and etc.

Dominik
Guest

Nice sample, thanks for publishing!
It seems like there is a small error in SiteDAO line 21. It should be ‘q.orderBy(cb.desc(path));’

Leonardo Shikida
Guest

thanks!

André
Guest

Thanks for this very helpful sample.
Little typo @:

}else if (sortOrder.equals(SortOrder.DESCENDING)){
021 q.orderBy(cb.asc(path));

should be q.orderBy(cb.desc(path));

Leonardo Shikida
Guest

thanks!

Daniel Gonzalez
Guest

I’m having some problems for sorting and filtering Date fields. Do I have to do something specific for Date?

Thank you for your excellent post.

Leonardo Shikida
Guest

Hi Daniel

Recently, I had to add a date filter to a column. My solution was some sort of a hack, but it seems to work. Check it out here – http://leonotepad.blogspot.com.br/2015/03/adding-date-range-filter-to-primefaces.html

zafar
Guest

Thank you man for sharing

Edson
Guest

Hello!
This implementation works with richfaces 4?
Or in primefaces only?

Leonardo Shikida
Guest

only primefaces

Marlon Pessoa
Guest

Excellent! Can you post the the full project for download? Thanks.

Leonardo Shikida
Guest

Sorry, the project source code belongs to my client :-(

Jon
Guest

Hi Leonardo,

Did you find the same for the data schedule component?

I need to data bind the Primefaces schedule component
http://www.primefaces.org/showcase/ui/data/schedule.xhtml

Any suggestions greatly appreciated.

wpDiscuz