Primefaces LazyDataModel Hibernate 5 ile kullanımı
Primefaces LazyDataModel
Primefaces Datatable aracında verilerimizin hepsinin aynı anda listelenmemesini isteyebiliriz.Çok veri olduğunda ekranda kilitlenmeler yapacaktır.Bu durumlarda LazyDataModel ile verilerin Datatable aracımıza parça parça gelmesini sağlayabiliriz.Örneğin 1 ile 10 arası 10 ile 20 arası gibi.
LazyDataModel implementi
Hibernate ile lazy load işlemi yapacağım.Hibernate 5 ile createcriteria() metodu deprecated duruma geldi. Ben örneğimde CriteriaBuilder,CriteriaQuery... kullanarak veritabanı sorgularımı çalıştırdım.
Gerekenler
Daha önceki yazımda hibernate ile temel crud işlemlerini göstermiştim(Yazıyı Oku).
Bu yazıdaki projeyi indirelim. Bu proje üzerine ben customer.xhtml, CustomerBean,CustomerService,CustomerDao şeklinde sınıflarımı ekledim.Önceki yazıda Service Dao , beans.xml ile dependency injection kısımlarını detaylı anlatmıştım bu yazıda lazy data model üzerine yoğunlaşacağım.
Customer.xhtml
Customer sayfam için bir datatable aracı kullandım.Burada unutmamanız gereken datatable aracında lazy=true Bu sayede oluşturacağımz LazyDataModel sınıfındali load metodu tetiklenecek ve parça parça veri çekme işlemimiz gerçekleşecek.Bir diğer kısım ise value=bean.lazydatamodel burada önceki örneklerimizden farklı olarak List değil LazyDataModel bağlıyoruz.Her sayfada kaç veri listeleneceğini ayarlamak için rows=”8″ etiketini kullanmalıyız.
<p:dataTable id="dtCustomer" value="#{customerBean.lazyModelCustomer}" lazy="true" var="customer" editable="true" paginator="true" paginatorPosition="bottom" rows="8" currentPageReportTemplate="{startRecord}-{endRecord} records are listed. Totally: {totalRecords} records" paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}">
Customer Xhtml Son hali
<!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:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui"> <h:head></h:head> <body> <h:form id="form"> <p:dataTable id="dtCustomer" value="#{customerBean.lazyModelCustomer}" lazy="true" var="customer" editable="true" paginator="true" paginatorPosition="bottom" rows="8" currentPageReportTemplate="{startRecord}-{endRecord} records are listed. Totally: {totalRecords} records" paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"> <p:column headerText="ID"> <h:outputText value="#{customer.personId}" /> </p:column> <p:column headerText="First Name" filterBy="#{customer.firstname}" sortBy="#{customer.firstname}"> <h:outputText value="#{customer.firstname}" /> </p:column> <p:column headerText="Last Name"> <h:outputText value="#{customer.lastname}" /> </p:column> <p:column headerText="Job"> <h:outputText value="#{customer.job}" /> </p:column> <p:column headerText="City"> <h:outputText value="#{customer.city}" /> </p:column> <p:column headerText="Adress"> <h:outputText value="#{customer.address}" /> </p:column> </p:dataTable> </h:form> </body> </html>
Customer Bean
Bean sayfamızda xhtml ile bağlanılacak lazyDataModelimi başlatmam gerekli.
private LazyDataModel<ZzAtakanPerson> lazyModelCustomer;
Sayfa ilk açıldığında ekranda verilerimi görmek istiyorum init() metodunda lazy modelimi başlatıyorum
@PostConstruct public void init() { lazyModelCustomer = new CustomerLazyDataModel(customerService); }
CustomerLazyDataModel
LazyDataModel verilerin parça parça gelmesi için implement edilmesi gereken sınıfımızdır.
getRowKey() : Satır seçme işleminde tekrar etmeyen id alanımız
getRowData() : rowKey değerine göre parça verideki seçilen satırın entity objesi
load (int first, int pageSize, String sortField, SortOrder sortOrder,Map<String, Object> filters)
load metodu primefaces datatable aracı tarafından çağırılır bu metodda satır sayısı ve data listesini çekmeliyiz.İçindeki parametreleri açıklayalım.
first : Listelenecek verideki ilk satır numarasıdır. 1 ile 10 arasını listele dersek first : 1 , 10 ile 20 arası dediğimizde 20dir.
pageSize: Xhtml sayfasında rows=8 olarak belirttiğimiz yer burasıdır.her sayfada ne kadar eleman olacağı bilgisi
sortField: Sıralama yapılacak kolon bilgisi.Ekranda AD’a göre sırala dendiğinde buraya AD seklinde kolon adı gelir
sortOrder: Ekranda Sıralama yapıldığında Azalana veya Artana bilgisi gelir.ASC veya DESC
filters : Bu alanda ekranda filtre yapılan alanlara göre key value seklinde kolon adı-arama içeriği döner.AD-Atakan gibi..
package com.atakancoban.model; import java.util.List; import java.util.Map; import org.primefaces.model.LazyDataModel; import org.primefaces.model.SortOrder; import com.atakancoban.orm.ZzAtakanPerson; import com.atakancoban.service.CustomerService; public class CustomerLazyDataModel extends LazyDataModel<ZzAtakanPerson> { private static final long serialVersionUID = 1928300515443607970L; private CustomerService customerService; public CustomerLazyDataModel() { } public CustomerLazyDataModel(CustomerService customerService) { this.customerService = customerService; } @Override public Object getRowKey(ZzAtakanPerson object) { return object.getPersonId(); } @Override public ZzAtakanPerson getRowData(String rowKey) { try { @SuppressWarnings("unchecked") List<ZzAtakanPerson> list = (List<ZzAtakanPerson>) getWrappedData(); for (ZzAtakanPerson obj : list) { if (obj.getPersonId().toString().equals(rowKey)) return obj; } } catch (Exception e) { System.out.println("getRowData method error" + e.getMessage()); e.printStackTrace(); } return null; } @Override public List<ZzAtakanPerson> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) { List<ZzAtakanPerson> list = null; try { int rowCount = customerService.getCountOfCustomer(filters); this.setRowCount(rowCount); list = customerService.getDataOfCustomer(first, pageSize, sortField, sortOrder, filters); } catch (Exception e) { this.setRowCount(0); System.out.println("customarLazyModel LOAD method error" + e.getMessage()); e.printStackTrace(); } return list; } public CustomerService getCustomerService() { return customerService; } public void setCustomerService(CustomerService customerService) { this.customerService = customerService; } }
CustomerServiceImpl
Servis sınıfında lazy data model için gerekli olan COUNT ve LİST döndüren metodlarımı tanımladım.
@Override public List<ZzAtakanPerson> getDataOfCustomer(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) throws Exception { return customerDao.getDataOfCustomer(first, pageSize, sortField, sortOrder, filters); } @Override public int getCountOfCustomer(Map<String, Object> filters) throws Exception { return customerDao.getCountOfCustomer(filters); }
CustomerDaoImpl
GetDataOfCustomer Metodu
Hibernate 5 ile createCriteria() metodu deprecated duruma geldi.
// Criteria crit = session.createCriteria(ZzAtakanPerson.class);
CriteriaBuilder : Query üzerinde like,order gibi düzenlemeler yapmamızı yöneten sınıf
CriteriaQuery<ZzAtakanPerson> : Criteria bizden ne dönecekse o Entity ister.Yani ben bu queryden zzAtakanPerson türünde bir satır veya liste olarak veri döndürebilirim.
Root<ZzAtakanPerson> : Burada root aslında base sorgumuz oluyor. select * from tabloadı.Ihtıyaca göre root üzerinde where,orderby vs yaparak veriler çağırılıyor.
Örneğin : critQuery.select(root); root nesnemiz zzAtakanPerson olduğuna göre (select * from zzAtakanPerson) aslında bu işlem.
Temel olarak veri çekme akışı şu şekilde
critQuery.select(root);
critQuery.where(criteriaBuilder.like(root.get(“KOLONADI”), “%ARA_KELİME%”)); //KOLONADI like işlemi> ARAKELİME
critQuery.orderBy(criteriaBuilder.asc(root.get(“KOLONADI”))); //Asc olarak KOLONADI alanını sırala
session.createQuery(critQuery).setFirstResult(first).setMaxResults(first + pageSize) .getResultList();// criterai query çalıştır ve first ile (first+pagesize) kadar veri getir (1 ile 10 arasındakiler gibi)
@Override public List<ZzAtakanPerson> getDataOfCustomer(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) throws Exception { List<ZzAtakanPerson> customerList = null; try { Session session = getCurrentSession(); //deprecated // Criteria crit = session.createCriteria(ZzAtakanPerson.class); // new version // builder oluştur CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder(); // tablo ne dönecek entity.class liste veya tek satır dönebilir . CriteriaQuery<ZzAtakanPerson> critQuery = criteriaBuilder.createQuery(ZzAtakanPerson.class); // select*from entity.class düşün root sorgu Root<ZzAtakanPerson> root = critQuery.from(ZzAtakanPerson.class); // select root yani select * from entity.class şuan aşağıda // where,orderby eklendi critQuery.select(root); // Where if (!filters.isEmpty()) { Iterator<Entry<String, Object>> iterator = filters.entrySet().iterator(); while (iterator.hasNext()) { Entry<String, Object> entry = iterator.next(); critQuery.where(criteriaBuilder.like(criteriaBuilder.upper(root.get(entry.getKey())), "%" + entry.getValue().toString().toUpperCase(new Locale("tr", "TR")) + "%")); critQuery.where(criteriaBuilder.like(root.get(entry.getKey()), "%arakelime%")); } } // Order By if (sortField != null && !sortField.isEmpty()) { if (sortOrder.equals(SortOrder.ASCENDING)) { // crit = crit.addOrder(Order.asc(sortField)); // order by - yukarıda select,where yapılmıştır şimdi order // eklendi yine criteriabuilder. critQuery.orderBy(criteriaBuilder.asc(root.get(sortField))); } else { // crit = crit.addOrder(Order.desc(sortField)); critQuery.orderBy(criteriaBuilder.desc(root.get(sortField))); } } // query first , max parameterleri ve getResultList() eski hali // list()di customerList = session.createQuery(critQuery).setFirstResult(first).setMaxResults(first + pageSize) .getResultList(); } catch (Exception e) { throw new Exception("getDataOfCustomer() method error " + e.getMessage(), e); } return customerList; }
GetCountOfCustomer Metodu
Row count için gerekli olan metodumuzda da mantık aynı fakat değişen yerler var
CriteriaQuery<Long> : Burada sorgumuzdan bir entitiy almayacağız sadece rakam alacağız o nedenle Long olarak verdim
Bir değişen yer ise
critQuery.select(criteriaBuilder.count(root)); burada root sorgumuzun sadece sayısını alacağız.criteraiBuilder ile bunu yaptım.
Temel olarak veri çekme akışı
critQuery.select(criteriaBuilder.count(root));
critQuery.where(criteriaBuilder.like(root.get(“KOLONADI”), “%ARA_KELİME%”)); //KOLONADI like işlemi> ARAKELİME
Burada orderBy yok çünkü toplam sayıya etkisi yok sadece where koşulu gerekli
session.createQuery(critQuery).getSingleResult().intValue(); //Sadece rakam döneceği için singleResult
@Override public int getCountOfCustomer(Map<String, Object> filters) throws Exception { int customerTotalCount = 0; try { Session session = getCurrentSession(); //deprecated // session.createCriteria(ZzAtakanPerson.class).setProjection(Projections.rowCount()); // Builder oluştur CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder(); // query oluştur ne dönüyor entitiy.class CriteriaQuery<Long> critQuery = criteriaBuilder.createQuery(Long.class); // select * from (entity.class) gibi düşün root class Root<ZzAtakanPerson> root = critQuery.from(ZzAtakanPerson.class); // select cümlesi - builder ile count al , tüm data için root // yazılır. critQuery.select(criteriaBuilder.count(root)); // Where if (!filters.isEmpty()) { Iterator<Entry<String, Object>> iterator = filters.entrySet().iterator(); while (iterator.hasNext()) { Entry<String, Object> entry = iterator.next(); critQuery.where(criteriaBuilder.like(criteriaBuilder.upper(root.get(entry.getKey())), "%" + entry.getValue().toString().toUpperCase(new Locale("tr", "TR")) + "%")); } } Query query = session.createQuery(critQuery); // uniqueResult değil getSingleResult() gelen tek veriyi al obje de // olabilir if (query.getSingleResult() != null) { customerTotalCount = ((Long) query.getSingleResult()).intValue(); } else customerTotalCount = 0; } catch (Exception e) { throw new Exception("getCountOfCustomer() method error " + e.getMessage(), e); } return customerTotalCount; }
Örnek LazyDataModel Projesi
Filtre Örneği
Filtre ve sıralama yapılmadan datatable durumu
Filtre olarak “ata” kelimesi yazılı.Datatable durumu.
Filtre olarak “a” harfi yazılı ve datatable durumu.
Sıralama Örneği
Azalana sıralama örneği
Artana sıralama örneği
lazyLoad(“Kolay Gelsin 🙂 “);
Projenin kaynak kodlarını indirebilirsiniz.
jsf,hibernate,primefaces,spring soru öneri>@ŞükrüÇakmak