Persisting objects

Persisting transient objects may be achieved in various ways. JDBC allows to store and retrieved object values.

Having larger projects these tasks become increasingly tedious. It is thus desired to automate these tasks while still using JDBC™ for the low level transport layer.

The following sections start with a single class hibintro.v1.model.User:

Figure 932. A basic User class.

Todo: Ref/Fig/classUser.fig


Object relational mapping (ORM) denotes the process of mapping instances of classes to relational table data. In our current example we may draw a simple implementation sketch:

Figure 933. Mapping properties to attributes.

Todo: Ref/Fig/mapUser.fig


This is far too simplistic. What about integrity constraints?

Figure 934. Annotating integrity constraints

Todo: Ref/Fig/mapUserIntegrity.fig


We start with the following hibintro.v1.model.User class lacking integrity constraints completely:

package hibintro.v1.model;
	@Entity
	public class User {
	String uid;
	public String getUid() {return uid;}
	public void setUid(String uid) {this.uid = uid;}

	String cname;
	public String getCname() {return cname;}
	public void setCname(String cname) {this.cname = cname;}

	/**
	* Hibernate/JPA require a default constructor. It has has to be implemented
	* if any non-default constructor has been defined
	*/
	public User() {}

	/**
	* @param uid See {@link #getUid()}.
	* @param cname See {@link #getCname()}.
	*/
	public User(String uid, String cname) {
	this.uid = uid;
	this.cname = cname;
	}
	}

Persisting objects with Hibernate requires a org.hibernate.Session instance ❶. It happens between the start ❷ and commit ❸ of a transaction being derived from that session:

package hibintro.v1.run;

	...
	public class PersistSingleUser {

	public static void main(String[] args) {
	final org.hibernate.Session session ❶= HibernateUtil.createSessionFactory("hibernate.cfg.xml").openSession();

	final org.hibernate.Transaction transaction = session.beginTransaction();❷

	final hibintro.v1.model.User u = new User("goik", "Martin Goik");
	session.save(u);

	transaction.commit(); ❸
	}
	}

Executing the above code yields a runtime exception:

Exception in thread "main" java.lang.ExceptionInInitializerError
	at myhibernate.intro.run.PersistUser.main(PersistUser.java:14)
	Caused by: org.hibernate.AnnotationException: No identifier specified for entity: myhibernate.intro.model.User
	...
	at myhibernate.intro.util.HibernateUtil.buildConfiguration(HibernateUtil.java:17)
	at myhibernate.intro.util.HibernateUtil.<clinit>(HibernateUtil.java:9)

This runtime error is a little bit cryptic. The missing identifier refers to the absence of a primary key definition already mentioned in Figure 934, “Annotating integrity constraints ”. We define a key by annotating the uid property with a javax.persistence.Id annotation ❶:

package hibintro.v1.model;

	import javax.persistence.Entity;
	import javax.persistence.Id;

	...
	@Entity public class User {...
	@Id ❶
	public String getUid() {
	return uid;
	} ...

The careful reader will have noticed that we've annotated the getter method rather than the property uid itself. Hibernate / JPA can work both ways. Annotating a getter however offers additional support e.g. when logging for debugging purposes is required.

This time we are successful. Since we enabled the logging of SQL statements in Figure 929, “A basic persistence.xml JPA configuration file. ” Hibernate shows us the corresponding INSERT statement:

Hibernate: 
	insert 
	into
        User
        (cname, uid) sky
	values
        (?, ?)

Notice the (?,?) part of our log: This indicates the internal usage of JDBCjava.sql.PreparedStatement instances. Hibernate generates the following create table statement:

Figure 935. Database schema mapping instances of hibintro.v1.model.User.
CREATE TABLE User (
	  uid VARCHAR(255) NOT NULL PRIMARY KEY,
	  cname VARCHAR(255)
	  )