Can we do without ORM? Can we "just use SQL" instead?
SQL and ORM
Sometimes, we encounter the following statement:
I don’t need ORM, I can just use SQL instead.
There are two essential problems with this line of thought:
-
An ORM solution like Hibernate is not in competition with SQL. Indeed, in Hibernate, we usually write queries in HQL, which is a feature-rich dialect of SQL DML. HQL is usually significantly less verbose and much more portable between databases than the native SQL dialect of your database. And in Hibernate Data Repositories, HQL can be type-checked at compilation time. But if you prefer to write queries in the native SQL dialect of your database, Hibernate has got you covered. Any place HQL is used, SQL may also be used. It’s extremely common for application programs to use a mix of HQL and SQL.
-
The most essential purpose of ORM is to map rectangular SQL result sets to interconnected graphs of Java objects. SQL itself can’t do this. And handwritten code for this sort of mapping is typically verbose, fragile, and difficult to optimize after the fact. ORM lets us express reusable mappings declaratively. In Hibernate, such mappings are specified using annotations or XML. Performance-related concerns such as association fetching and caching may be specified separately, in a way which reduces the impact of later performance optimization.
At one extreme, some people use Hibernate for object/relational mapping but write all their queries in native SQL. That’s not very common, and it’s not our recommendation, but it’s certainly an allowed point in the solution space.
On the spectrum
Some application programs use entity classes more than others. Here there are two extremes:
-
Some programs never return graphs of entities from queries. Instead, query results are represented in a simpler, "flattened" form, possibly as Java
record
s. Here, eachrecord
models a query result, not an entity. Associations between entities are not explicitly represented within the flattened form. These programs might still use entity classes for simple CRUD. -
Other programs use an entity domain model for everything. That is, every query returns a graph of entity instances with some associations fetched via a SQL
join
, and some left unfetched. These programs place great importance on having a typed representation of the problem domain model reified in Java.
Clearly, the second sort of program benefits quite a lot more from the use of an ORM solution like Hibernate. We can certainly still use Hibernate in the first sort of program, and it does still offer some advantages, but we certainly wouldn’t describe ORM as a necessity there.
We’ve described these scenarios as "extremes" for a reason: we think it’s much more common to have some queries that return entity graphs, and some which return flat representations. Indeed, this is the way Hibernate is intended to be used, and it’s the true sweet spot for ORM.
Is ORM necessary?
I suppose you might think we’ve avoided the essential issue: do I ever really need to use ORM?
Well, there are two senses in which the answer might be "no".
-
First, strictly speaking, I never absolutely need to use any higher-level abstraction when a lower-level API is available. But of course, the entire goal of software engineering is to develop meaningful and useful abstractions which help reduce engineering effort, and so this isn’t really a particularly helpful observation. On the contrary, if some higher-level abstraction helps make my application program code more maintainable, then yes, I "need" it.
-
Second, whether this is indeed the case in this instance — that is, whether ORM actually results in more maintainable code — is at least somewhat contextual. There is a class of application program that doesn’t benefit much from representing persistent data using graphs of entity objects, and can get by with
record
types representing rows of SQL result sets. On the other hand, if my program does use entity classes, I am going to need object/relational mapping, and then the choice is between a powerful, mature, full-featured solution like Hibernate and … what inevitably leads me down the path towards my own homegrown ORM.
Before Hibernate existed, it simply wasn’t the case that Java enterprise developers "just used SQL", never bumped into the object/relational "mismatch", and never struggled with persistence. On the contrary, homegrown ORMs or proto-ORMs were quite ubiquitous and almost uniformly quite terrible. Hibernate didn’t replace "just SQL"; it replaced a whole range much worse implementations of ORM.
Ultimately, the overwhelming majority of Java developers still find ORM useful for the kinds of scenarios we typically encounter in enterprise software development. That doesn’t necessarily mean that you need it for the particular problem you’re working on right now. If what you’re doing is already working well, we’re definitely not going to tell you to do anything different. But when maintaining your handwritten object/relational mappings starts slowing you down, Hibernate is here to help.
Conversely, if ORM or Hibernate is getting in your way, by all means use something else. It’s great that you’re using Hibernate — but that doesn’t mean you have to use it everywhere.