Friday, December 22, 2006

Customizing Simple EJB 3.0 Entities and Tables

The Java Persistence API does a good job mapping entities and fields in default mode to tables in a database. But sometimes you need to specify the name and columns of a table (maybe to take advantage of an existing schema). Using annotations in your entities makes this easy to implement. As an example, let us suppose you need to represent an employee in a database:
With EJB 3.0, you begin by writing an entity for the employee. The Employee class is a basic POJO, but annotations added to it are what make it persistable as we desire.

@Entity
@Table(name="EMP")
public class Employee implements Serializable {
@Column(name="NAME")
private String name;
@Column(name="SAL")
private long salary;
@Column(name="COMM")
@Basic(fetch=FetchType.LAZY)
private String comments;
@Basic(fetch=FetchType.LAZY)
@Column(name="PIC")
@Lob
private byte[] picture;
@Column(name="HIRED")
@Temporal(value = TemporalType.DATE)
private Date dateHired;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="EMP_ID")
private Long id;
@Transient
private transient String nameString;

@Override
public int hashCode() { ... }
@Override
public boolean equals(Object object) {...}
@Override
public String toString() {...}
}

The simple class above is much of what you need to represent an entity in a database. @Entity tells the persistence provider that the data of this class shall be saved in the database. @Table specifies which table shall be used. The entity must be serializable so that RMI and reflection features of Java technology can be used.
Within the table, @Column names the column for each of the attributes that shall be persisted. You can use lazy fetching to improve performance when reading entities from databases - lazy fetching skips reading columns in regular reads until the attribute is actually accessed. So it is recommended for attributes that will not be used much - in our example, pictures and comments.
The API makes it really easy to work with large objects (BLOBs and CLOBs). When we upload a picture for an employee, it'll be a huge resource. @Lob is used to indicate that a special column be allocated in the table for this kind of data.
@Temporal is used to convert dates to and from SQL types. I would not need it if I used javax.sql.Date type to represent dates in my application.
@Id specifies that the attribute/column is the primary key in the table. @GeneratedValue indicates that the primary key should be automatically generated for us. AUTO allows the persistence provider to choose a strategy (either SEQUENCE, IDENTITY, or TABLE), although you can use them directly yourself.
@Transient or the transient qualifier for properties indicates that the attribute should not be persisted. Variables like this are used to hold results of processes that use other variables and not expected to change much - helps improve efficiency if you don't have to recalculate data every time it is requested.
As usual, you need to implement hashCode(), toString(), and equals(), overriding what Object provides. Also advisable is implementing the Comparable interface on the class for sorting algorithms.

This is a basic single-entity implementation; we know that seldom do applications have single entities like this, so in the next few posts, relationships will be summarized.