Question

I'm wondering what is the right way to deal with dataTables that take input in a Hibernate/JPA world. As far as I can tell, one of the following three choices is causing the whole house of cards to fall apart, but I don't know which one is wrong.

  • Semi-automatic transaction and EntityManager handling via a custom JSF PhaseListener that begins and commits transactions around every request
  • Putting editing components inside a dataTable
  • Using request-scoped managed beans that fetch their data from a request-scoped EntityManager (with some help from PrettyFaces to set IDs on the request scoped beans from their URLs)
  • Backing a dataTable with a request-scoped bean instead of a view- or session-scoped bean.

I see an ICEfaces dataTable demo using JPA but they are both manually managing the transactions and not displaying editing components by default. You click on the row which causes an object to be nominated for editability and then when you hit "save" it manually reconnects the object to the new EntityManager before manually triggering a save. I see the click-to-edit function here as giving us a way to ensure that the right object gets reattached to the current session, and I don't know how one would live without something similar.

The impression I'm getting about the new ICEfaces 3.0 ace:dataTable (née PrimeFaces 2.0 dataTable) is that it is intended to be used in a View- or Session-scoped bean, but I don't see how one could get around StaleObjectState and/or LazyInitializationExceptions if one has model objects coming out of the DAO in request A and EntityManager A and then being modified or paged in by request B with EntityManager B.

I suppose it might work under Java EE through some kind of deep fu, but I don't have the luxury of upgrading us from Tomcat 6 to anything fancier right now (though it is my intent in the long run). We're also not about to start using Spring or Seam or whatever the other cool stuff is. ICEfaces is enough weird for us, probably too much weird honestly.

So to sum up, which of these is the wrong choice? The request-scoped entity manager, the request-scoped dataTable or using editing components inside a dataTable? Or is something else really at fault here?

Was it helpful?

Solution

If you'd ask me, the prime fault seems to be sticking to an almost bare Tomcat when your requirements seem to scream for something a little fancier. The mantra is normally that you use Tomcat when you don't need "all that that other stuff", so when you do need it, why keep using a bare Tomcat?

That said, the pattern really isn't that difficult.

  • Have a view scoped backing bean
  • Obtain the initial data in an @PostConstruct- (when there are no parameters like IDs) or PreRenderViewEvent method in combination with view parameters
  • Use a separate Service class that uses an entity manager to obtain and save the data
  • Make the entity manager "transaction scoped"
    • Without EJB/CDI/Spring:
      • Obtain a new entity manager from an entity manager factory for every operation.
      • Start a (resource local) transaction, do the operation, commit transaction, close entity manager.
  • Return the list of entities directly from your backing bean, bind the edit mode input fields of the table to the corresponding properties of the entity.
  • When updating a single row, pass the corresponding entity to the update method of your service. Apart from the overhead of getting an entity manager, starting the transaction etc, this basically only calls merge() on the entity manager.

Realize that outside the service you're working with detached entities all the time. There is thus no risk for any LazyInitializationExceptions. The backing beans need to be in view scope so the correct (detached!) entity is updated by JSF, which your own code then passes to the service, which merges it into the persistence context.

The flow for persisting is thus:

View state               View scope         Transaction scoped PC
Facelet/components       Backing Bean       Service
      Strings ------> Detached entities --> Attached entities

(the flow for obtaining data is exactly the reverse)

Creating the Service this way is a little tedious and a kind of masochist exercise though. For an example app and just the two methods (get and update) discussed above it wouldn't be so bad, but for any sizable app this will quickly run out of hand.

If you are already adding JSF and JPA to Tomcat, just do yourself a favor and use something like TomEE. This is barely bigger than Tomcat (25MB vs 7MB) and contains all the stuff you're supposedly trying to avoid but in reality need anyway.

In case you absolutely can't upgrade your Tomcat installation (e.g. the product owner or manager thinks he owns the server instead of the developers), you might want to invest in learning about CDI. This can be easily added to your war (just one extra jar) and let's you abstract away lots of the tedious code. One thing that you also could really use is a JTA provider. This too can be added separately to your war, but the more of this stuff you add the better you'll be off by just using TomEE (or alternatives like GlassFish, Resin, JBoss, etc).

Also see this article, which covers various parts of your requirements: Communication in JSF 2.0

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top