The trend in recent years is to model the entities in application’s object model and to use the database for storing the persistence information defined in the entity layer. This helps you create loosely coupled application components, richer relationship between objects, support various databases etc. With tools like Hibernate, it is really easy to map an object model into a relational database schema.
Base Class for Common Fields
Defining entities for persistence layer is similar to defining any object model. Look for common properties that all objects can share. While defining the entities, use OOPS concepts like inheritance and polymorphism.The focus should be to achieve the following:
- Avoid code duplication in the persistence layer
- Implement common functionality in the domain
- Audit each and every change properly
- Handle concurrency to avoid data loss/data getting overridden
Here are some of the best practices:
Base Class for Common Fields
Create base class containing fields like id, version, timestamp and other common fields. Use inheritance to avoid code duplication. Also use JPA annotations wherever possible.
Polymorphism
Have a hierarchy of classes to be used while defining the object model. There will be cases when one base class is not enough. On the other hand, you can have entities which might not require all the fields defined in the base class.
DAO Pattern
Encapsulate logic for accessing data in an object or set of related objects. The goal should be to have database related logic in the DAO classes.
Dependency Injection
Query data by injecting the entity class that the DAO will be querying, along with defining the generic type.
Pagination
Write a generic implementation to support pagination. The goal should be to push pagination all the way down to the database and reduce resource consumption.
Auditing
Add audit fields/annotations to the objects which require auditing. This helps you keep track of objects- when are they created, who created them, who modified the object and when.
Lazy Loading
Use this when you do not want to query all data from an association when an object is loaded.
Eager Loading
Mark the associations with FetchType EAGER incase the association is needed mandatorily.
Querying Associations
Use Lazy loading in general, but if you need to load the association at query time, you can set the query params to make the association as Eager.
Persistence Layer with Behavior
Let persistence layer own the behavior of entities. It means that apart from creating the object graph you should write code to operate on the domain objects.
In my next post I will cover how Domain Driven Design can be used to achieve this easily.
Concurrency
Use optimistic concurrency control with versioning. You can use version numbers, or timestamps, to detect conflicting updates and to prevent lost updates. If you don’t configure Hibernate to use optimistic locking, it uses no locking at all. So, in this case the last update always wins.
Hope you enjoy designing persistence layer, keeping these key points in mind!