Updating a List of Domain Entities in Struts 2

I've been working on Quadran a lot, and I'm creating pages for editing lists of entities. The CRUD example from the Struts 2 Showcase application does this in a very simple manner. It recreates all of the entities every time you update the list. That's fine for an example but unusable in real life.

In real life we have to present entities from our database and then put the values back into the same entities, and update our database. We can't just re-create them.

The Entity

So, we'll start with a simple domain object and assume that we're using something like JPA or Hibernate to persist it via a Data Access Object (DAO), and that it contains a property called "id".

That's all there is to the action. In the prepare we get the List of MyEntity objects and then put them into a map keyed on MyEntity.id. Pretty straight forward. The Map is the key to the whole process. We will use the OGNL EL notation to access that Map and fill the values back into it when a user submits the form.

How OGNL Fills in our Domain Objects

In this we iterate over the myEntities List. On the textfield tag we set the name to "myEntitiesMap['%{id}'].value", this would result in something that looks like "myEntitiesMap['1'].value". When the user submits the form Struts2 will evaluate this name as so:

Expression

Result

myEntitiesMap

This will call getMyEntitiesMap() on our EditMyEntitiesAction.

['1']

This will call get("1") on the Map that was returned by getMyEntitiesMap(), which will return a MyEntity object.

.value

Will call setValue() on the MyEntity object returned previously. Setting the value of the property to the value that was submitted by our user.

It took me a while to figure out how to do this. I was struggling over how to get the values back into the "List" of entities in my action, then I hit on the idea of putting them into a Map keyed on the id of the entities, and voila, it all fits together.

What's Not Here

This is by no means an enterprise ready update mechanism. The primary things I've left out is validation. This can be added by implementing a validate() method in our Action. Best practice would be to delegate that validation to some other bean responsible for the management of MyEntity objects.

But I found out that it still create a new instance of myEntities, and save all the values in form to the new myEntities. If you don't display some filed in the form, the field will be null, and the old data is gone. I haven't try your 'Map' solution yet, does your method keep the old data in myEntities even you don't display them in the jsp page?

Looking at your example and reading the thread on the forum I think this might work. I'll have to give it a try. I'll admit I have done very little with the type conversion support in S2. I really haven't had time to dig into it.

You can have a separate bean for the form properties. Take a look at the ModelDriven documentation.

Another alternative is to create the bean as a property of your action in your prepare() method. Then in your form you can reference the properties of your bean in your tags with 'name="bean.propety"'.