I just use open session in view. You can still retrieve stuff outside a transaction. I explicitly call update to persist. On Feb 12, 2012 7:54 AM, "Bas Gooren" <b...@iswd.nl> wrote:
> Hi All, > > I have an architectural question about wicket, DDD and the service layer. > > Let's say we have a simple JPA entity (Customer), and a few simple CRUDL > screens. > For database access, we have a DAO layer (CustomerDao) which delegates to > an EntityManager, and provides some convenience methods for searching. > We also like to have clear boundaries, so we have a thin service layer > which wraps persist() and delete() calls in a transaction before forwarding > them to the DAO layer (@Transactional, as provided by guice-persist). > > A wicket model fetches one or more customers (by id or by running a > search), and attaches to a form. In the form we use PropertyModels which > push their changes to the entity, and in onSubmit() we call > service.persist(entity). > This means that the actual changes to the model happen outside of the > transaction (in wicket code), and within the transaction (/service layer) > we merely call persist() and flush(). > > Then parts of the app need something a bit more advanced, so we decide to > apply parts of DDD and put logic where it belongs (on the domain models). > However, some logic coordinates multiple models, so we add a domain- or > application-service for that. > The good thing about DDD is that it's a lot more clear what happens > (intent). We now realize that having a persist() method on a entity-based > service now looks like a bit of a code smell, since it does not capture > intent at all. Also, since the changes to the model happen in wicket, > before the service layer is called, I feel that the service layer is not > doing anything to act as a boundary. We might as well mark the persist() > method on our daos @transactional and remove the service layer. > > The only clean way to fix this seems to be either: > (a) using DTO's so the UI/wicket is not actually modifying domain entities > upside: the state of the domain is not modified by wicket itself > downside: duplication of models (actual model + DTO); > downside: validation is currently set-up in wicket by scanning fields > for validation annotations, so we would need to duplicate those on the DTO? > > (b) using a concept from CQRS: sending commands to the domain through a > bus. This clearly and cleanly defines the intent and captures the exact > change. > upside: the state of the domain is not modified by wicket itself > downside: likely overkill for what we are trying to achieve; lot of > extra complexity > > (c) wrapping the entire request in a transaction > upside: easy to implement > downside: since anything in the request can fetch a dao, read some > entities and modify them, this means we can lose track of what happens in a > request; > downside: feels like moving backwards > > (d) simplify by removing thin services and, where necessary, putting more > logic in the dao's > upside: simple api contract: want to save/update an entity? use the dao > directly > downside: dao's contain logic which does not really belong there > downside: if at some point we really do need a service, the api > contract becomes less clear: for X and Y you can use the dao, for Z you > have to use a service > > (a) and (b) provide a way to capture a change and execute all of the > change inside a transaction. > > So my question to the list is: what are your experiences with this? How do > you deal with this in simple to moderately complex webapps? > > Thanks for reading! >