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.
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?
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.
@PostConstruct
- (when there are no parameters like IDs) or PreRenderViewEvent
method in combination with view parametersmerge()
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