I'm developing a new Java web application and I'm exploring new ways (new for me!) to persist the data. I mostly have experience with JPA & Hibernate but, except for simple cases, I think this kind of full ORM can become quite complex. Plus, I don't like working with them that much. I'm looking for a new solution, probably closer to SQL.
The solutions I'm currently investigating :
But there are two use cases I'm worrying about with those solutions, compared to Hibernate. I'd like to know what are the recommended patterns for those use cases.
Person
entity. Person
has an associated Address
entity. Address
has an associated City
entity. City
entity has a name
property.The full path to access the name of the city, starting from the person entity, would be :
person.address.city.name
Now, let's say I load the Person entity from a PersonService
, with this method :
public Person findPersonById(long id) { // ... }
Using Hibernate, the entities associated to the Person
could be lazily loaded, on demand, so it would be possible to access person.address.city.name
and be sure I have access to this property (as long as all the entities in that chain are not nullable).
But using anyone of the 3 solutions I'm investigating, it's more complicated. With those solutions, what are the recommended patterns to take care of this use case? Upfront, I see 3 possible patterns:
All the required associated children and grandchildren entities could be eagerly loaded by the SQL query used.
But the issue I see with this solution is that there may be some other code that needs to access other entities/properties paths from the Person
entity. For example, maybe some code will need access to person.job.salary.currency
. If I want to reuse the findPersonById()
method I already have, the SQL query will then need to load more information! Not only the associated address->city
entity but also the associated job->salary
entity.
Now what if there are 10 other places that need to access other information starting from the person entity? Should I always eagerly load all the potentially required information? Or maybe have 12 different service methods to load a person entity? :
findPersonById_simple(long id) findPersonById_withAdressCity(long id) findPersonById_withJob(long id) findPersonById_withAdressCityAndJob(long id) ...
But then everytime I would use a Person
entity, I would have to know what has been loaded with it and what hasn't... It could be quite cumbersome, right?
In the getAddress()
getter method of the Person
entity, could there be a check to see if the address has already been loaded and, if not, lazily load it? It this a frequently used pattern in real life applications?
Are there other patterns that can be used to make sure I can access the entities/properties I need from a loaded Model?
I want to be able to save a Person
entity using this PersonService
's method :
public void savePerson(Person person) { // ... }
If I have a Person
entity and I change person.address.city.name
to something else, how can I make sure the City
entity modifications will be persisted when I save the Person
? Using Hibernate, it can be easy to cascade the save operation to the associated entities. What about the solutions I'm investigating?
Should I use some kind of dirty flag to know what associated entities also have to be saved when I save the person?
Are there any other known patterns useful to deal with this use case?
Update : There is a discussion about this question on the JOOQ forum.
MyBatis, Spring, Entity Framework, SQLAlchemy, and Sequelize are the most popular alternatives and competitors to Hibernate.
Difference Between JPA and HibernateJPA is responsible for managing relational databases in Java applications. Hibernate is an ORM tool used for saving the state of the Java object in the database. It is defined under the javax. persistence package.
If your project does not have an intensive report generation and/or you're comfortable with ORM mapping, Hibernate is your best choice. Otherwise, I strongly recommend checking out for alternatives. You may find wonderful things outside the mainstream. by Jonatas de Moraes Junior @honatas.
This kind of problem is typical when not using a real ORM, and there is no silver bullet. A simple design approach that worked for me for a (not very big ) webapp with iBatis (myBatis), is to use two layers for persistence:
A dumb low-level layer: each table has its Java class (POJO or DTO), with fields that maps directly to the table columns. Say we have a PERSON
table with a ADDRESS_ID
field that points to an ADRESS
table; then, we'd have a PersonDb
class, with just a addressId
(integer) field; we have no personDb.getAdress()
method, just the plain personDb.getAdressId()
. These Java classes are, then, quite dumb (they don't know about persistence or about related classes). A corresponding PersonDao
class knows how to load/persist this object. This layer is easy to create and maintain with tools like iBatis + iBator (or MyBatis + MYBatisGenerator).
A higher level layer that contains rich domain objects: each of these is typically a graph of the above POJOs. These classes have also the intelligence for loading/saving the graph (perhaps lazily, perhaps with some dirty flags), by calling the respective DAOs. The important thing, however, is that these rich domain objects do not map one-to-one to the POJO objects (or DB tables), but rather with domain use cases. The "size" of each graph is determined (it doesn't grow indefinitely), and is used from the outside like a particular class. So, it's not that you have one rich Person
class (with some indeterminate graph of related objects) that is used is several use cases or service methods; instead, you have several rich classes, PersonWithAddreses
, PersonWithAllData
... each one wraps a particular well-limited graph, with its own persistence logic. This might seem inefficient or clumsy, and in some context it might be, but it happens often that the use cases when you need to save a full graph of objects are actually limited.
Additionally, for things like tabular reports, (specific SELECTS that return a bunch of columns to be displayed) you'd not use the above, but straight and dumb POJO's (perhaps even Maps)
See my related answer here
The answer to your many questions is simple. You have three choices.
Use one of the three SQL-centric tools you've mentioned (MyBatis, jOOQ, DbUtils). This means you should stop thinking in terms of your OO domain model and Object-Relational Mapping (i.e. entities and lazy loading). SQL is about relational data and RBDMS are pretty good at calculating execution plans for "eager fetching" the result of several joins. Usually, there isn't even a lot of need for premature caching, and if you do need to cache the occasional data element, you can still use something like EhCache
Don't use any of those SQL-centric tools and stick with Hibernate / JPA. Because even if you said you don't like Hibernate, you're "thinking Hibernate". Hibernate is very good at persisting object graphs to the database. None of those tools can be forced to work like Hibernate, because their mission is something else. Their mission is to operate on SQL.
Go an entirely different way and choose not to use a relational data model. Other data models (graphs for instance) may better suit you. I'm putting this as a third option, because you might not actually have that choice, and I don't have much personal experience with alternative models.
Note, your question wasn't specifically about jOOQ. Nonetheless, with jOOQ, you can externalise the mapping of flat query results (produced from joined table sources) to object graphs through external tools such as ModelMapper. There's an intersting ongoing thread about such an integration on the ModelMapper User Group.
(disclaimer: I work for the company behind jOOQ)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With