Tuesday, October 14, 2014

Simple PrimeFaces CRUD Guide - READ & DELETE

In the second part of my PrimeFaces CRUD guide, I talk about the Read and Delete operations on a database. That is, to view the records of a database (either all of them or search for certain ones), select records and delete them.

In the case of my application, the idea goes like this;
the administrator navigates to the show-users webpage. Automatically, the page loads the records from the database and displays them. The admin can also search for users by username, name or email. Naturally, the display of users updates to show the new records. In any case, the admin can select a user to delete. After pressing the Delete button, the user is deleted from the database, the users' display is updated and a Growl is shown.

A video demonstrating how this works is shown below:


JSF Code

I'll be using code snippets in this post instead of a single screenshot, but you can find the full gist here.

Let's start with the form. It has only two components, a panelGrid and a dataTable.


PanelGrid



There isn't much to explain here, the 3 columns accommodate the three components inside the panelGrid; the selectOneRadio, inputText and commandButton.

selectOneRadio

When one clicks a radio button, its itemValue is passed to the selectOneRadio and thus it can take only three values, username, name and email. By default the selectOneRadio is deselected, but I'll show you later how you can default to a certain value.

inputText

The searchTerm is what the admin enters to search the database. Like I showed in the video demo, if it's empty it just shows all the records. The title attribute is a tooltip that's displayed if the mouse cursor hovers over the component.

commandButton

The interesting part here is the update attribute. It's used to force an AJAX update to the specified component, in this case the showUsers dataTable, causing it to only show the records I searched for.

DataTable

Attributes

Let's take a look at the dataTable attributes. The value one, is linked to a List that holds the List of objects that are fetched from the database. The tableStyle auto-stretches the dataTable to fit its contents and parent component. 

The var attribute is the iterator of the dataTable and the rowKey is used to detect which row is selected. It needs to be a unique identifier, so the user's ID field is ideal considering there are no duplicates in the database.

Columns

I think the columns are self-explanatory. The first column though is how the radioButton is added and the selection-mode attribute means that only one of the rows can be selected.

Footer

The footer of the dataTable naturally spans below and across the data. I've added indicators to show how many users there are in the database, and how many we see when we search for terms.

The deleteUser commandButton is what I'm really proud of. I don't know if there's an easier way to do this but I managed to make it work how I want it. It may be trivial to some people but I've never worked with web technologies before.

When I want to delete a user from the database, I want both the dataTable to update and the Growl to display the deletion message. The update attribute though can only update one(?) component. So what I thought was; update just the Growl but set the commandButton's ajax attribute to false! This would force the page to refresh and then reload the data from the DB. 

JSF Backing Bean

Full gist can be found here, I'll just show the key methods below.

Constructor

In the constructor you can see that I set the searchBy value to username. This defaults the radio buttons to pre-select a specific value. It's quite handy if we forget to select what to search by.

SearchByField

The if statement is a work-around to exception handling, this code here should be re-written with exceptions I think, throwing one when the search input text is empty.

PostConstruct

In the first part of my guide, I mentioned that EJBs cannot be instantiated in the backing bean's constructor. This is why I'm using the PostConstruct annotation, the init method is called after the backing bean is constructed and in this case fetches the table records and counts them.

Entity Session Bean

In the enterprise java bean (gist here), lies the code that communicates with the database. The show-users webpage has some calls to the EJB that queries the DB using JPQL.

JPQL Search

The findAllUsers method's query is the equivalent of SELECT * FROM Users, we fetch all of the records.

It returns a list that holds the results of the specific query. The RolesAllowed annotation specifies that only the app users with the admin role can call this method.

When we want to search by name, a similar query to SELECT * FROM Users WHERE id LIKE '%sth%' needs to be constructed. The task is accomplished like so:


Java8 Search

Now that we have Java 8 and GlassFish 4.1 has support for it, we can use the Collection improvements (streams, filtering, lambdas) to accomplish the same thing as above. In the example below, I fetch all of the records from the database and store them in a List.

Each element of the list is streamed and filtered with a lambda expression, if it matches the argument it's placed in a new List.



Keep in mind though, if the database was large there would probably be a performance issue here. I hardly think the Java 8 streams are as optimised as a native SQL query.

Delete

In order to delete the selected user, the object must be passed as an argument and then execute the query. The User argument is an object in the backing bean code that has its properties set when the admin checks a row in the dataTable.

When the query is executed though, it returns an integer that denotes how many rows were affected. Since I don't need the affected rows (I just delete one user at a time), I just assign the query to an integer and don't use it.

Coming up next...

In the third and final part of this guide, I'll be talking about the the UPDATE operation of CRUD, updating an existing DB row. I haven't written the code for that yet, so it may take some time for the 3rd part to come up. I have to see how I can transfer data from one webpage to another.

No comments:

Post a Comment