In the
first post of this gotcha series, I had discussed some of the issues around making entities
publicly immutable, by not exposing direct setters to the layers above. This approach has its own set of advantages and offers a big safety net to the domain model. The domain model can then be manipulated only through the methods published by the domain contracts. While still on the subject of immutability of domain models, I thought I would discuss about the other cousin of immutable entities that plays a very big role in making your domain driven design more supple.
Enter Value Objects.
While an object-oriented domain model focuses on the
behavior of entities, the relational persistence model manages
object identities. And a successful marriage of the two paradigms is the job of a good ORM framework. But not all entities need to maintain their identities - their behaviors depend only upon the values they carry.
Eric Evans calls them
Value Objects.
Value objects are an integral part of any object oriented model, while they are somewhat obscure in the relational persistence model. It is a real challenge to have a successful representation of value objects as reusable abstractions in the OO domain model, while transparently storing them in the relational model with minimum invasiveness on part of the programmer. Value objects increase the reusability of the domain model and JPA offers a flexibile programming model to make their persistence transparent to the developer. The big advantages with value objects are that you need not manage their identities or their lifetimes - both of them are the same as the entities which own them.
Modeling a Value Object with JPAConsider a sample model snippet where an
Employee
has-an Address
- both of them are designed as separate domain objects in the model. After a careful analysis of the domain, we find that addresses are never shared, i.e. each employee will have a unique address. Hence the relational model becomes the following monolithic table structure :
create table employee ( )In the relational model, we need not have any identity for an address - hence it can be seamlessly glued into the employee record. While in the OO model, we need to have a fine grained abstraction for
Address
, since the purpose of the OO model is to have the most faithful representation of how the domain behaves. The
Address
class will have its own behavior, e.g. the format in which an
Address
gets printed depends upon the country of residence, and it makes no sense to club these behaviors within the
Employee
domain entity. Hence we model the class
Address
as a separate POJO.
class Address {
private String houseNumber;
private String street;
private String city;
private String zip;
private String country;
}
and an
Employee
has-an
Address
..
class Employee {
private Address homeAddress;
}
JPA makes it really easy to have a successful combination of the two models in the above relationship. Just add an
@Embedded
annotation to the
Address
property in
Employee
class. This will do all the magic to make all individual address attributes as separate columns in the
Employee
table. And of course we can use all sorts of annotations like
@AttributeOverride
to change column names between the class and the table.
@Entity
class Employee {
@Embedded
@AttributeOverrides( {
@AttributeOverride(name = "street",
column = @Column(name = "home_street")),
@AttributeOverride(name = "city",
column = @Column(name = "home_city")),
@AttributeOverride(name = "zip",
column = @Column(name = "home_zip"))})
private Address homeAddress;
}
Modeling with JPA allows independent evolution of the OO domain model and relational persistence model. Don't ever try to enforce the relational paradigm into your domain - you are likely to end up in the swamps of the ActiveRecord modeling.
Collection of Value ObjectsIn the above example, the entity
Employee
has a one-to-one association with
Address
- hence it was easy to embed the address attributes as columns within the
Employee
table. How do we handle a one-to-many association between an entity and a value object ? Let us have a look at this scenario ..
A
Project
is an entity which abstracts an active project in a company. And the company raises Bills periodically to its clients for all the projects that it executes. The
Bill
object is a value object. We just have to raise bills and keep a record of all bills raised till date. A
Bill
does not have an identity, it's only the bill date and amount that matters. But we need to associate all bills with the project for which it is raised. This clearly warrants a 1..n association in the relational model as well. And the lifecycle of all bills is coupled to the lifecycle of the owning project. Sharing of bills is not allowed and we do not need to manage identities of every bill.
Using Hibernate specific annotations, here's how we can manage a set of value objects owned by an entity.
@Entity
class Project {
@CollectionOfElements
@JoinTable(name="project_bill",
joinColumns = @JoinColumn(name="project_pk")
)
@AttributeOverrides( {
@AttributeOverride(name = "billNo",
column = @Column(name = "project_bill_no")),
@AttributeOverride(name = "billDate",
column = @Column(name = "project_bill_date")),
@AttributeOverride(name = "raisedOn",
column = @Column(name = "raised_on")),
@AttributeOverride(name = "amount",
column = @Column(name = "project_bill_amount"))}
)
@CollectionId(
columns = @Column(name = "project_bill_pk"),
type = @Type(type = "long"),
generator = "sequence"
)
private Set<Bill> bills = new HashSet<Bill>();
}
Bill
is not an entity - it is a simple POJO, which can be reused along with other owning entities as well. And if we want an inverse association as well, we can maintain a reference to the owning project within the
Bill
class.
@Embeddable
public class Bill {
@Parent
private Project project;
}
The database contains a table
project_bill
, which keeps all bills associated with a project indexed by
project_pk
. In case we need a sequencing of all bills, we can have a sequence generated in the
project_bill
table itself through the
@org.hibernate.annotations.CollectionId
annotation.
Value objects are an immensely useful abstraction. Analyse and find out as many value objects as you can in your domain model. And use the power of JPA and your ORM implementation to map them into your persistent model. The more value objects you can dig out, less will be the effort in managing identities and controlling lifetimes for each of them.
Decoupled Value Object Instantiation ModelsThere are some situations where value objects tend to be numerous in number. Here is an example :
Every employee has-a designation.
Designation
is a value object in our domain model and in a typical organization we have a limited number of designations. We make a separate abstraction for designation, since a designation has other behaviors associated with it e.g. perks, salary bracket etc. Here we go ..
@Embeddable
class Designation {
}
and the
Employee
entity ..
@Entity
class Employee {
private Designation designation;
}
What about the relational model ? We can employ a nice little trick here ..
Clearly many employees
share a designation - hence, theoretically speaking, Designation is an
entity (and not a value object) in the relational model, having a 1..n association with the Employee table. But, as Eric Evans has suggested in his discussion on
Tuning a Database with Value Objects, there may be situations when it is better to apply denormalization techniques for the sake of storing collocated data. Making Designation an entity and wiring a relationship with Employee through its identity will store the Designation table in a far away physical location, leading to extra page fetches and additional access time. As an alternative, if access time is more critical than physical storage, we can store copies of Designation information with the Employee table itself. And, doing so, Designation turns into a Value Object for the relational model as well! In real world use cases, I have found this technique to be an extremely helpful one - hence thought of sharing the tip with all the readers of this blog.
However, we are not done yet - in fact, the subject of this paragraph is decoupled instantiation models for value objects, and we haven't yet started the tango. We first had to set the stage to make Designation a value object at both the levels - domain and persistence models. Now let us find out how we can optimize our object creation at the domain layer while leaving the persistence level to our JPA implementation.
In a typical use case of the application, we may have bulk creation of employees, which may lead to a bulk creation of value objects. One of the cool features of using JPA is that we can adopt a completely different instantiation strategy for our OO domain model and the relational persistent model. While persisting the value object
Designation
, we are embedding it within the
Employee
entity - hence there is always a copy of the value object associated with the persistent
Employee
model. And this is completely managed by the JPA implementation of the ORM. However, for the domain model, we can control the number of distinct instances of the value object created using the
Flyweight design pattern. Have a look ..
@Embeddable
class Designation {
@Transient
private static Map<String, Designation> designations
= new HashMap<String, Designation>();
Designation() {
}
public static Designation create(..) {
Designation d = null;
if ((d = designations.get(..)) != null) {
return d;
}
}
}
We have a flyweight that manages a local cache of distinct designations created and controls the number of objects instantiated. And since value objects are immutable, they can be freely shared across entities in the domain model. Here is an example where using JPA we can decouple the instantiation strategy of the domain objects from the persistence layer. Although we are storing value objects by-value in the database, we need not have distinct in-memory instances in our domain model. And, if you are using Hibernate, you need not have a public constructor as well. For generation of proxy, Hibernate recommends at least package visibility, which works fine with our strategy of controlling instantiation at the domain layer using flyweights.
Value objects are invaluable in making designs more manageable and flexible. And JPA provides great support in transparent handling of instantiation and persistence of value objects along with their owning entities. With a rich domain model, backed up up by a great ORM like Hibernate that implements JPA, we can get the best of both worlds - powerful OO abstractions as well as transparent handling of their persistence in the relational database. I had earlier
blogged about injecting ORM backed repositories for transparent data access in a domain model. In future installments of this series, I plan to cover more on this subject describing real life use cases of applying domain driven design techniques using JPA and Hibernate.