Enterprise Java Development@TOPIC@

Chapter 28. Mapping Temporal Types

28.1. Mapping Temporal Types
28.2. Summary

This chapter will take you through mapping temporal (i.e. Dates) to columns in the dataabase.

  1. Put the following class with three temporal types in place. Note that although the names of the properties indicate an intent to store DATE, TIME, and TIMESTAMP information, their Java datatype does not offer enough clues to the provider to make the distinction.

    package myorg.entityex.annotated;
    
    
    import java.util.Calendar;
    import java.util.Date;
    import javax.persistence.*;
    @Entity
    @Table(name="ENTITYEX_SHARK")
    public class Shark {
        @Id @GeneratedValue
        private int id;
        private Calendar aDate;
        private Date aTime;
        private Date aTimestamp;
        
        public int getId() { return id; }
        public Shark setId(int id) {
            this.id = id; return this;
        }
        
        public Calendar getDate() { return aDate; }
        public Shark setDate(Calendar date) {
            this.aDate = date; return this;
        }
        
        public Date getTime() { return aTime; }
        public Shark setTime(Date time) {
            this.aTime = time; return this;
        }
        
        public Date getTimestamp() { return aTimestamp; }
        public Shark setTimestamp(Date timestamp) {
            this.aTimestamp = timestamp; return this;
        }
        
        @Override
        public String toString() {
            return new StringBuilder()
                .append("aDate=").append(aDate.getTime())
                .append(", aTime=").append(aTime)
                .append(", aTimestamp=").append(aTimestamp)
                .toString();
        }
    }
  2. Add the new entity class to the persistence unit

    
            <class>myorg.entityex.annotated.Shark</class>
  3. Build the module and note the default schema created. The aDate, aTime, and aTimestamp where all created using a timestamp column type.

        create table ENTITYEX_SHARK (
            id integer generated by default as identity,
            aDate timestamp,
            aTime timestamp,
            aTimestamp timestamp,
            primary key (id)
        );
  4. Add the following test method to your existing JUnit test case. This test method just prints the temporal fields of the original object and then of the object coming form the database.

        @Test
    
        public void testTemporal() {
            log.info("testTemporal");
            Shark shark = new Shark()
                .setDate(new GregorianCalendar(1776, Calendar.JULY, 4))
                .setTime(new Date())
                .setTimestamp(new Date());
            em.persist(shark);
            log.info("initial object=" + shark);
            
            //flush commands to DB and get new instance
            em.flush(); em.detach(shark);
            Shark shark2 = em.find(Shark.class, shark.getId());
            log.info("object from DB=" + shark2);
        }
  5. Rebuild the module with the new test method. Observe the dates printed and how they are not quite what we are looking for. The Calendar date looks okay, but the time contains both time and date (because it is declared as a timestamp)

     -testTemporal
    Hibernate: 
        insert 
        into
            ENTITYEX_SHARK
            (id, aDate, aTime, aTimestamp) 
        values
            (null, ?, ?, ?)
     -initial object=aDate=Thu Jul 04 00:00:00 EST 1776, aTime=Sun Feb 24 02:21:44 EST 2013, aTimestamp=Sun Feb 24 02:21:44 EST 2013
    Hibernate: 
        select
            shark0_.id as id4_0_,
            shark0_.aDate as aDate4_0_,
            shark0_.aTime as aTime4_0_,
            shark0_.aTimestamp as aTimestamp4_0_ 
        from
            ENTITYEX_SHARK shark0_ 
        where
            shark0_.id=?
     -object from DB=aDate=Thu Jul 04 00:00:00 EST 1776, aTime=2013-02-24 02:21:44.861, aTimestamp=2013-02-24 02:21:44.861
  6. Add Temporal specifications to the three properties.

        @Temporal(TemporalType.DATE)
    
        private Calendar aDate;
        @Temporal(TemporalType.TIME)
        private Date aTime;
        @Temporal(TemporalType.TIMESTAMP)
        private Date aTimestamp;
  7. Rebuild the module and note the new database schema created. Our three fields now have more distinct values.

        create table ENTITYEX_SHARK (
            id integer generated by default as identity,
            aDate date,
            aTime time,
            aTimestamp timestamp,
            primary key (id)
        );
  8. In looking at the output from the entity pulled from the database, each of the temporals has the desired granularity. Note that the first printed output is of the Date objects before they have been massaged by the database.

     -testTemporal
    Hibernate: 
        insert 
        into
            ENTITYEX_SHARK
            (id, aDate, aTime, aTimestamp) 
        values
            (null, ?, ?, ?)
     -initial object=aDate=Thu Jul 04 00:00:00 EST 1776, aTime=Sun Feb 24 02:19:47 EST 2013, aTimestamp=Sun Feb 24 02:19:47 EST 2013
    Hibernate: 
        select
            shark0_.id as id4_0_,
            shark0_.aDate as aDate4_0_,
            shark0_.aTime as aTime4_0_,
            shark0_.aTimestamp as aTimestamp4_0_ 
        from
            ENTITYEX_SHARK shark0_ 
        where
            shark0_.id=?
     -object from DB=aDate=Thu Jul 04 00:00:00 EST 1776, aTime=02:19:47, aTimestamp=2013-02-24 02:19:47.112
                </listitem>
            
                <listitem><para></para>
    <programlisting language=""><![CDATA[

In this chapter we were able to map temporal (i.e., Date) values to the right level of granularity for their purpose. We could assign Date, Time, or Timestamp granularity and the proper bits were removed from the objects pulled from the database.