Friday, September 28, 2007

Domain Modeling with JPA - The Gotchas - Part 2 - The Invaluable Value Objects

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 JPA

Consider 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 (
  //..employee specific columns
  //..
  //..address specific columns
)


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.


// immutable
class Address {
  private String houseNumber;
  private String street;
  private String city;
  private String zip;
  private String country;

  //.. getters
  //.. no setter
  //.. behaviors
}



and an Employee has-an Address ..


class Employee {
  private Address homeAddress;
  //.. other attributes
}



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;
  //.. other attributes
}



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 Objects

In 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 {
  //.. attributes

  @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 Models

There 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 {
  //.. attributes
  //.. behavior
  //.. immutable
}



and the Employee entity ..


@Entity
class Employee {
  //.. attributes
  private Designation designation;
  //.. other attributes
  //..
}



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 {
  //.. persistent attributes

  @Transient
  private static Map<String, Designation> designations
    = new HashMap<String, Designation>();

  // package scope
  Designation() {
    //.. need this for Hibernate
  }

  // factory method
  public static Designation create(..) {
    Designation d = null;
    if ((= designations.get(..)) != null) {
      return d;
    }
    // create new designation
    // put it in the map
    // and return
  }
  //..
  //..equals(), hashCode() .. etc.
}



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.

15 comments:

Unknown said...

Great explanation. Thank you very much.

Matt Corey said...

Excellent series of articles so far -- I love this stuff :)... I wanted to add that the Designation example may also be naturally represented in your domain model as an Enum, as long as all of the Designation types are known at design-time... this would then be easily mapped to your Employee table with the @Enumerated annotation...

It is a bit annoying that the default mapping will use the ordinal value of the enum (1, 2, 3, which usually will be nonsense), but it can be overridden with '@Enumerated (STRING)'...

M

Unknown said...

"I wanted to add that the Designation example may also be naturally represented in your domain model as an Enum"

Yes, it could well have been represented as an Enum. But as I indicated in the post, Designation may be richer than a simple String. It may contain other information like salary hi and lo figures for the designation, which warrants a more rich and a separate abstraction for itself. However the idea was to illustrate 2 things :-

a) Shared objects can sometimes be made Value Objects for performance reasons
b) Instantiation models of the domain layer and persistent layer are decoupled and can follow their own strategies. As I have described, we can optimize domain object instantiation using patterns like Flyweight, while the JPA implementation can use all sorts of reflection magic to instantiate the values for each database record.

Anonymous said...

In your Employee/Designation example is it safe to say that Employee objects loaded from the database will not have a Designation object from the cache?

Anonymous said...

Excellent post! Thanks.

I agree that value objects are important and nice, and I myself strive to model with them, when it makes sense.

One thing though, that irritates me, is that I am not able to write finders on value objects themselves. I can only use @Entity modelled objects, in queries.

Unknown said...

"One thing though, that irritates me, is that I am not able to write finders on value objects themselves. I can only use @Entity modelled objects, in queries."

According to the principles of domain driven design, all queries (finders) should be encapsulated within Repositories. And a Repository should be based on the Aggregate Root. And Value Objects are almost never modeled as aggregate roots. Hence it is only natural that you write finders on entities, which, in turn pull out respective value objects.

Anonymous said...

Yes, I know, ... but :-)

Practically, I find situations, where it appears to me, that a finder on the value object would make must sense to me.

If I really have that need, one can then argue, that I have modelled it wrongly, and it really shouldn't be a value object.

I was just reflecting on that I have more than once, needed to convert a value object type into an entity, to write the queries, I wanted.

Unknown said...

@Tech Per:

Interesting .. will be great if u can share one of the scenarios. I think the key issue is sharing, because that is when the identity management becomes important. In the example of Employee-Designation, note that Designation is theoretically shared by Employees, but I have used denormalization to convert sharing into copying. This is driven by performance considerations, and is not the rule, but an exception. On the more general side, since value objects have their lifetimes coupled with the entities they own, it is more logical to have finders on the entities themselves.

Unknown said...

[OT] It would be nice if you could use a specific blogger label for this series of articles, to make it easier to bookmark. Great job, BTW, I'm looking forward to future installments.

Unknown said...

@Rafael:
Good suggestion! I have the label jpa-gotcha-series for this.

Anonymous said...

Why not just have Employee entity to implement interface Address and leave the POJO to be similar to the table?

Unknown said...

@alternative:
Interfaces model an is-a relationship. While Address, by nature is a pure value object. Does "Employee is-a Address" sound logical ?

Anonymous said...

It is purely philosophical issue. You can have 2 interfaces Employee and Address and their implementation - POJO EmployeeWithAddress.

Anonymous said...

And by the way, if you decide that your Employee is uniquely identified by his/her email then Employee is virtually Email. What is it to you - real human being with his guts, etc.?

Tech Per said...

Is it possible, with JPA or Hibernate, to map a OneToOne association from an Entity to a Value object? The entity in its own table and the value object in its own table.

A bit like the example you have with @CollectionOfElements mapping, but where it is not a collection.

?