Lazy Loading JSF DataTable

I’ve actually blogged about this topic three years ago and introduced the PagedListDataModel. That solution worked at that time with some flows in design but now after three years, I’ve a much better solution to the same problem. Using PrimeFaces DataTable it’s a piece of cake to load millions of data lazily, just set the lazy to true and provide a LazyDataModel. Here’s is how it works.

<p:dataTable var="car" value="#{tableBean.lazyModel}" paginator="true" rows="10"
			dynamic="true" lazy="true">

	<p:column>
		<f:facet name="header">
			<h:outputText value="Model" />
		</f:facet>
		<h:outputText value="#{car.model}" />
	</p:column>

	<p:column>
		<f:facet name="header">
			<h:outputText value="Year" />
		</f:facet>
		<h:outputText value="#{car.year}" />
	</p:column>

	<p:column>
		<f:facet name="header">
			<h:outputText value="Manufacturer" />
		</f:facet>
		<h:outputText value="#{car.manufacturer}" />
	</p:column>

	<p:column>
		<f:facet name="header">
			<h:outputText value="Color" />
		</f:facet>
		<h:outputText value="#{car.color}" />
	</p:column>
</p:dataTable>

And the lazyModel;

public class TableBean {

	private LazyDataModel<Car> lazyModel;

	public TableBean() {
		/**
		* Test with one hundred million records.
		* In a real application use an sql Count query to get the row count.
		*/
		lazyModel = new LazyDataModel<Car>(100000000) {

			/**
			 * Dummy implementation of loading a certain segment of data.
			 * In a real applicaiton, this method should access db and do a limit based query
			 */
			@Override
			public List<Car> fetchLazyData(int first, int pageSize) {
				logger.info("Loading the lazy car data between {} and {}", first, first+pageSize);

				List<Car> lazyCars = new ArrayList<Car>();
				populateLazyRandomCars(lazyCars, pageSize, first);

				return lazyCars;
			}
		};
	}

	public LazyDataModel<Car> getLazyModel() {
		return lazyModel;
	}

	private void populateLazyRandomCars(List<Car> list, int size, int first) {
		for(int i = 0 ; i < size ; i++) {
			int offset = i + first;
			list.add(new Car("Model_" + offset, getRandomYear(), "Brand_" + offset, "Color_" + offset));
		}
	}
}

That’s just it, whenever a paging event occurs with ajax, your fetchLazyData implementation will be called with the offset and pageSize. In a real application, you need to use your specific data access methods to load a chunk of data between a certain interval. For example in JPA api setMaxResults(pageSize) and setFirstResult(first) would do the trick. Also you need to define how many virtual records are there to be displayed so that PrimeFaces DataTable can create it’s paginator using that value, as an example a count/projection query could be used.

So to sum up, with PrimeFaces DataTable lazy loading capabilities even if you have billions of records, you can enable lazy loading very easily since number of all records are not relevant, only the records on the current datatable page is loaded.

There’s an online demo that demonstrates how to display one hundred million(100000000) records with this feature with paging happening less than a second.

2 Responses to Lazy Loading JSF DataTable

  1. fiorenzo says:

    Hi Cagatay,
    very good work!

    Is it possible to disable top or bottom scroller?
    Is it possible to detach the scroller from p:dataTable, to positioning this element in customized place on the page?
    ********
    And a paginator like gooogle for paging result of search??
    For website table-less, i use ul-li with a4j:repeat and rich:datascroller:
    don’t exist a jsf-datatable component without html table code….

    bye bye

  2. myfear says:

    In reply to your twitter question about facelets and websphere 6.1:

    You need to register shared libs. After that, configure a custom Classloader (parent first) and add the shared libs to it. Finished..

%d bloggers like this: