This post is part of a series I am writing on Domain Driven Design (DDD).
In my previous post on Value Objects I had mentioned that Value Objects can contain references to other entities and value objects.
I will show how to use Hibernate's features to define and use Value Objects. For illustration purposes I have taken a simple VO. If you look at any price label on any product, there are 2 consituents to it - a numerical price part and a alphabetical currency part. When paying for product, you end up multiplying the numerical part with the conversion rate of currency you pay to cashier.
Building from this example, I have an Order entity which has a Price value object. The price value object contains a reference to the Currency entity.
Order contains Price; Price refers a Currency
Order.java looks like
|
Definition of Price Value Object
Price is a value object. Notice the lack of any apparent identity columns (Primary keys).
|
Mapping ValueObjects in hbm files
All details of how to make Hibernate treat price as a value object is added to the hbm mapping files.
|
From the above mapping file the two things of interest are
- default-access="field"
- Component tag
A component is an object that is treated as a value type and not as an entity. This means that the fields of the component/value class would be persisted as part of some entity. In our case, fields of Price were persisted in Order entity/table since the Order owns all values in Price. Hibernate when creating the Order, creates a Price object and maps the values to it. This price is set into the order.
A nice feature with Hibernate components is that the same Price VO can be used with any other entity as well, since the owning entity (Order, XYZ etc) can always override mappings for Price fields. Also one component can contain another component within itself !
Using Components, any combination like Entity -> VO -> Entity or Entity -> VO -> VO etc can be created. This gives us powerful abstraction abilities to keep grouping fields into powerful domain objects and not be bound/limited by data model.
Technorati Tags: DDD, Domain Driven Design, Hibernate
3 comments:
Kaushik,
Great job on the post. Keep writing them. Looks like you have done too many hands-on on the whole thing. Way to go dude!
Hello!
Looks good. But when you want to use Inheritance and Polymorphism with value objects, hibernate does not support you.
When you read books like "Domain Driven Design" of Eric Evans or "Refactoring" of Martin Fowler I think you would agree that using this feature -- using inheritance with value objects -- is an important feature for programming with a rich object model.
But if one of the most known OR-Mappers like hibernate does not support that, I ask myself, what technologies do the previously named authors use to implement a rich object model?
Thank you.
Jörg
Ah, I found two workarounds for the inheritance problem.
One here: http://blog.xebia.com/2007/09/25/hibernate-component-value-object-inheritance-mapping/
and one that use Entities, that have the same public class-Interface like the Value Objects. It´s like this:
@Entity
public class Parent1 {
@Id
@GeneratedValue
private Long id;
@OneToOne(cascade = CascadeType.ALL)
private ValueObjectWO wo;
public ValueObjectWO getWo() {
return wo;
}
public void setWo(ValueObjectWO wo) {
this.wo = wo;
}
public Long getId() {
return id;
}
}
@Inheritance
@Entity
@AccessType("field")
public class ValueObjectWO {
@GeneratedValue
@Id
private Long id;
private final String someStringAttribute;
public ValueObjectWO(String attribute) {
this.someStringAttribute = attribute;
}
private ValueObjectWO() {
someStringAttribute = "xyz";
}
public String getSomeStringAttribute() {
return someStringAttribute;
}
}
@Entity
@AccessType("field")
public class ValueObjectSubWO extends ValueObjectWO{
private final String newField;
public ValueObjectSubWO (String inheritedParameter, String newField) {
super(inheritedParameter);
this.newField = newField;
}
private ValueObjectSubWO() {
super("");
newField = "newField";
}
public String getNewField() {
return newField;
}
}
Post a Comment