Domain Models
Domain modeling is a concept inseparably linked with persistence, it is in fact the domain model that is persisted. There are four key areas regarding the domain model
This section deals with the defining aspect, the other three areas are dealt with in other topics.
One of the first steps in an enterprise application is creating the domain model, this entails listing the entities in the domain and defining the relationships between them. Domain modeling can be complex but the idea is simple, a domain model is a conceptual image of the problem you are trying to solve, a object in a domain model need not be a physical object but just a concept used by your system. A relationship is an imaginary link between objects that need to "know" about one another. So in short a domain model describes the objects and there relationship but not how a system acts on the objects.
Business rules are then implemented by the session beans and MDBs as discussed previously, while the persistence API implements the domain model that the business rules act on. UML diagrams and formal class diagrams are popular methods of creating domain models.
I am going to use the ActionBazaar application from the book to explain domain modeling, I will not detail all the code just enough to understand the concept, the application has a number of activities
We can pick out the domain objects by looking for the nouns: seller, item, category, bidder, bid and order
![]() |
![]() |
Looking at the two pictures above will help in placing the links (relationships) between the objects, thus creating the domain model. Although this is a simple example, this could takes days on a more complex example. We end up with a domain model looking like the one below
The domain model is formed of a number of one-to-one, one-to-many and many-to-many relationships between the objects. Lets explain in more detail what each means
Objects | These are like Java objects, the can have behavior (methods) and state (instance variables), there could be hundreds of objects in a domain model. |
Relationships | This defines the relationship between one object and another, these relationships are indicated by the arrows in the above picture. A single arrow heads means that the relationship is unidirectional (one way) and having two arrow heads means the relationship is bi-directional. Words describing this are has, is part of, is member of, belongs to, etc |
Multiplicity or Cardinality | this refers to the multifaceted nature of relationships
|
Ordinality or Optionality | this determines whether an associated entity exists, the relationship may be optional, for an example a user many not have any bids for instance but he/she could have |
The EJB 3 Java Persistence API (JPA) is a meta-data driven POJO technology, which means the objects do need to implement an interface, extend a class, or fit into any framework pattern, they are just plain old java objects. You use annotations or XML to give the persistence provider the following information
A standard POJO domain object in Java would look like something below
POJO domain object | public class Category { // The rest of the setters and getters for each instance variable |
Although the POJO above is a acceptable Java domain object, there are a number of problems
The @Entity property converts a POJO in to an entity, it marks the POJO as a domain object that can be uniquely identified, all entities must have a public or protected no-argument constructor, the constructor is used to create a new entity instance by using the new operator. Entities also support the full OO features such as inheritance and polymorphism.
Entity inheritance | @Entity public class User { ... String userId; String username; ... } @Entity class Seller extends User { ... } |
The above example means that when the seller entity is persisted all the inherited fields are also persisted, be careful as the User entities could be saved on its own which may not be the desired affect, to prevent this you could make the User entity abstract, abstract entities cannot be instantiated or saved.
An entity maintains its state by using either fields or properties (via setter and getter methods), you cannot mix and match, so specify one of the other
field-based persistence | @Entity public class Category { @Id public long id; public String name; public Date modificationDate; public Category() {} } |
It is possible to stop a particular property from being persisted by marking the property (field-based) with the @Transient annotation or marking the getter in a property-based entity.
@Transient | @Entity public class Category { @Id public long id; public String name; public Date modificationDate; @Transient public Long userCount; public Category() {} } |
There are a number of data types that can be persisted
Types |
Examples |
Java Primitives | int, double, long |
Java Primitives wrappers | java.lang.Integer, java.lang.Double |
String Type | java.lang.String |
Java API serializable types | java.math.BigInteger, java.sql.Date |
User-defined serializable types | class that implements java.io.Serializable |
Array types | byte[ ], char[ ] |
Enumerated types | {SELLER, BIDDER, CSR, ADMIN} |
Collection of entity types | Set<Category> |
Embeddable class | Classes that are defined @Embeddable |
Every entity of the domain model must be uniquely identifiable, this is the same as using primary keys in a database each row is uniquely identified by is primary key, its also the same as in Java when using the equals to compare two different objects data. There are several ways of telling the persistence provider where the identity of an entity is stored.
@Id annotation | this marks the field (apply to the variable) or property (apply to the get method) as the identity of an entity. There are limitations on what you can use EJB 3 supports primitives, primitive wrappers and Serialization types likes java.lang.String, java.util.Date and java.sql.Date. The one thing this annotation cannot do is use more than one field or property value to identify an entity, this is commonly know as a composite key, to accomplish this you can use the @IdClass and @Embedded annotations |
@IdClass annotation | This annotation allows you to use more than one @Id annotation in a sensible, there is a problem when using more than one field is how do you compare two instances in an automated fashion. I have an example below so take a look |
@Embedded annotation | Using this annotation is like moving the @IdClass annotation right into your entity and using the identity fields nested inside it to store entity data. |
Examples |
|
@Id | @Entity public class Category { // Field @Id protected String name; // Property @Id public String getName() { return this.name; } ... } |
@IdClass | # CatgeoryPK class - this must be serialized public int hashCode() { |
@Embedded | # CatgeoryPK class - does not be serialized public int hashCode() { @Entity public class Category { public Category() {} // No name and createDate fields @EmbeddedId protected CategoryPK categoryPK; ... } |
The @Embeddable annotation is used to designate persistence objects that need not have an identity of their own, this is because they are identified by the entity objects that they are nested inside and never persisted or accessed on their own, for an example the address below is never accessed outside of using the User entity so there is no need for the address to have an identity of its own, this is what the @Embeddable annotation is used for.
@Embeddable | @Embeddable public class Address { protected String streetLine1; protected String streetLine2; protected String city; protected String state; protected String zip code; protected String country; ... } @Entity public class User { @Id protected Long Id; protected String username; protected String first name; protected String last name; @Embedded protected String Address address; protected String email; protected String phone; ... } |
There are a number of relationships a entity can have, below is a table describing the relation types and the corresponding annotation
Relationship type | Annotation |
One-to-One | @OneToOne |
One-to-Many | @OneToMany |
Many-to-One | @ManyToOne |
Many-to-Many | @ManyToMany |
The @OneToOne annotation is used to mark uni- or bidirectional one-to-one relationships, A unidirectional is pictured below
An example of this is
@OneToOne (unidirectional) | # Field-based
|
@OneToOne (bidirectional) | @Entity
|
The definition of the @OneToOne annotation is below
@OneToOne definition | @Target({METHOD,FIELD}) @Retention(RUNTIME) public @interface OneToOne { Class targetEntity() default void.class; CascadeType[] cascade() default {}; FetchType fetch() default EAGER; boolean optional() default true; String mappedBy() default ""; } Notes: Target - can use either property-based or field-based persistence targetEntity - tells the persistence provider what the related entity class is (optional) cascade - controls what happens to related data when the relationship is altered or deleted fetch - specifies when and how the related fields are populated from the database tables optional - tells the persistence provider if the related object must always be present mappedBy - specifies the owning side of the relationship |
The @OneToMany and @ManyToOne, in the relationship one of the entities will have two more more references of the other, this usually means that an entity has a collection-type-field such as a Set or List storing multiple instances of another entity. If the association between two entities is bidirectional, one side of the association is one-to-many and the opposite side of the association side of the association is many-to-one.
@OneToMany interface | @Target({METHOD, FIELD}) @Retention(RUNTIME) Note: |
@ManyToOne interface | @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface ManyToOne { Class targetEntity() default void.class; CascadeType[] cascade() default(); FetchType fetch() default EAGER; boolean optional() default true; } |
Example | @Entity public class Item { @Id protected Long itemId; protected String title; ... @OneToMany(targetEntity=Bid.class,mappedBy="item") protected Set<Bid> bids; ... } @Entity public class Bid { @Id protected Long bidId; ... @ManyToOne protected Item item; ... } |
The example above shows a bidirectional relationship, the @ManyToOne annotation on the item variable tells the persistence provider that more than one Bid entity could hold references to the same Item instance, for bidirectional one-to-many relationships ManyToOne is always the owning side of the relationship.
The @ManyToMany relationship means that both sides might have multiple references to related entities, these relationships can be either uni or bidirectional, the owning side is defined as the one with the mappedBy on the "subordinate" entity. The definition is the same as the OneToMany
@ManyToMany interface | @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface ManyToMany { Class targetEntity() default void.class; CascadeType[] cascade() default(); FetchType fetch() default LAZY; String mappedBy() default ""; } |
Example | @Entity public class Category { @Id protected Long categoryId; protected String name; ... @ManyToMany protected Set<Item> items; ... } @Entity public class Item { @Id protected Long itemId; protected String title; ... @ManyToMany(mappedBy="items") protected Set<Category> categories; ... } |
To summarize here is a table listing the elements that are available to each annotation
Element | @OneToOne |
@OneToMany |
@ManyToOne |
@ManyToMany |
targetEntity | Yes |
Yes |
Yes |
Yes |
cascade | Yes |
Yes |
Yes |
Yes |
fetch | Yes |
Yes |
Yes |
Yes |
optional | Yes |
No |
Yes |
No |
mappedBy | Yes |
Yes |
No |
Yes |
If you still find it hard to mapp the tables with the annotation here is what you are looking for in the table or when you create a table
many-to-one | user_id int foreign key references users |
one-to-one | user_id int unique foreign key references users billing_details_id int primary key foreign key references users Note: notice the unique and primary key which means the column will contain a unique value |
many-to-many | To reperesent a many-to-many association in a relational database you must introduce a new table called a link table create table user_billing_details ( |