jsfdatatableloadinggetter

How and when should I load the model from database for JSF dataTable


I've a data table as below:

<h:dataTable value="#{bean.items}" var="item">

I'd like to populate it with a collection from the database obtained from a service method so that it is immediately presented when the page is opened during an initial (GET) request. When should I call the service method? And why?

  1. Call it before page is loaded. But how?
  2. Call it during page load. How?
  3. Call it in the getter method. But it is called multiple times.
  4. Something else?

Solution

  • Do it in bean's @PostConstruct method.

    @Named
    @RequestScoped
    public class Bean {
    
        private List<Item> items;
    
        @Inject
        private ItemService itemService;
    
        @PostConstruct
        public void init() {
            items = itemService.list();
        }
    
        public List<Item> getItems() {
            return items;
        }
    
    }
    

    And let the value reference the property (not method!):

    <h:dataTable value="#{bean.items}" var="item">
        <h:column>#{item.property}</h:column>
    </h:dataTable>
    

    Or when you merely want to iterate without autogenerating HTML:

    <ui:repeat value="#{bean.items}" var="item">
        #{item.property}<br />
    </ui:repeat>
    

    In the @PostConstruct you have the advantage that it's executed after construction and dependency injection. So in case that you're using an EJB to do the DB interaction task, a @PostConstruct would definitely be the right place as injected dependencies would not be available inside a normal constructor yet. Moreover, when using a bean management framework which uses proxies, such as CDI @Named, the constructor may or may not be called the way you expect. It may be called multiple times during inspecting the class, generating the proxy, and/or creating the proxy.

    At least do not perform the DB interaction job in the getter, unless it's lazy loading and you really can't do anything else. Namely, it would be invoked during every iteration round. Calling the service method during every iteration round is plain inefficient and may end up in "weird" side effects during presentation and postbacks, such as old values from DB seemingly still sticking around in the model instead of new submitted values.

    If you rely on GET request parameters, then use <f:viewParam> and <f:viewAction> instead. See also Creating master-detail pages for entities, how to link them and which bean scope to choose.

    If you want to preserve the model (the items property) across postbacks on the same view (e.g. CRUD table/dialog), then make the bean @ViewScoped, else the model won't be in sync with the view when the same model is concurrently edited elsewhere. See also Creating master-detail table and dialog, how to reuse same dialog for create and edit.

    If you utilize JPA's @Version feature on the model, then you can catch OptimisticLockException to deal with it and show a message like "The data has been edited by someone else, please refresh/review if the desired changes are as intended". See also Letting the presentation layer (JSF) handle business exceptions from service layer (EJB).

    See also: