Recently we developed a web app that uses the following tech stack:
- hibernate as orm
- spring
- extjs (MVC javascript front end)
For 1 business object, let it be a Personnel, we have:
1) a Personnel class (hibernate)
2) PersonnelDTO (will explain why we needed this)
3) a Personnel javascript model for Extjs (I don't know may be other javascript UI frameworks does not need a model defined)
Need for number 2 arised when we couldn't deal with sending hibernate objects back and forth, dealing with sessions and circular references etc. etc.
Plus, in some cases you need a fully filled Personnel object (full fields joined), sometimes just a few fields and a relation. Sometimes you need all the info to process a Personnel but you can't send it all the way to the client (security, privacy reasons). So we used DTO's to decouple model objects and objects that will be sent through the wire.
Adding-removing a field in such a project design becomes very tedious and error prone. Adding a field requires:
- add to DB tables
- add to model object
- add to DTO
- add to model -> DTO converter (when it's a field that can't be automatically mapped) regarding different scenarios that requires different amount of information about model
- add to Extjs model
- add to CRUD forms on the page
- add to client and server validators…
Isn't there a better approach to building similar applications? We are thinking of starting a new project and don't want to make the same mistakes.
Best Answer
I am working on a mid-sized project (150k LoC), with a similar setup:
We are facing similar problems.
In general, there is only little to no help for that. If you are using ORM, you have to use the
@Entity
-POJOs. If you do not want to expose these objects to the outside, there aren't many options:1) As you already do: use
DTO
s - but there is the disadvantage of mapping fields and keeping fields in sync 2) Instantiate a new Domainobject - as said above:@Entities
are POJOs and copy over those fields, you want to expose.Some of our application is grid over data, so there isn't always the need for fully fledged domain objects and sometimes you need a bunch of attributes from several objects. For such cases there is the possibility to work with
Constructor expressions in the SELECT clause
(see specification). So you could build aggregate-objects (or however you want to name theseDTO
s) which could span across multiple tables and where each attribute is associated to one column of your resultset. In this case thenew
object isn't necessarily an@Entity
. It has to provide only a constructor which takes all of the columns. (Note to myself: try this out for@Entities
).This would be best solved via reflection: copy over all fields in the new object from the old one. Done.
The following is highly subjective:
That said, we now have to take a look at the frontend: Since the advent of MV*-frameworks on the client-side, the question rises, where to put the stress on: client-side vs server-side validation or using both. Here is a nice talk from yeahuda Katz about »the tale of the two MVCs«.
If you go the client-side road, you haven't a duplication of "models", you have client-side-models and "persistence-objects" (
@Entities
)To sum it up:
Modern applications are complex.