Hibernate Types: Appendix A - Harnessing Hibernate
by James Elliott, Timothy M. O'Brien, Ryan FowlerHibernate makes a fundamental distinction between two different kinds of data in terms of how they relate to the persistence service: entities and values.
This excerpt is from Harnessing Hibernate . This guide is an ideal introduction to Hibernate, the framework that lets Java developers work with information from a relational database easily and efficiently. Databases are a very different world than Java objects, and with Hibernate, bridging them is significantly easier. This new edition lets you explore the system, from download and configuration through a series of projects that demonstrate how to accomplish a variety of practical goals.
An entity is something with its own independent existence, regardless of whether it’s currently reachable by any object within a Java virtual machine. Entities can be retrieved from the database through queries, and they must be explicitly saved and deleted by the application. (If cascading relationships have been set up, the act of saving or deleting a parent entity can also save or delete its children, but this is still explicit at the level of the parent.)
Values are stored only as part of the persistent state of an entity. They have no independent existence. They might be primitives, collections, enumerations, or custom user types. Since they are entirely subordinated to the entity in which they exist, they cannot be independently versioned, nor can they be shared by more than one entity or collection.
Notice that a particular Java object might be either an entity or a value—the difference is in how it is designed and presented to the persistence service. Primitive Java types are always values.
Here is a smattering of information about the built-in types, showing how they relate Java classes to SQL column
types. We present samples of the variability between databases, but are
not trying to show every variant; check out the source code for all the
dialect implementations in org.hibernate.dialect for
the definitive details (look for
registerColumnType( ) calls).
Hibernate’s basic types fall into a number of groupings:
- Simple numeric and Boolean types
These correspond to the primitive Java types that represent numbers, characters, and Boolean values, or their wrapper classes. They get mapped to appropriate SQL column types (based on the SQL dialect in use). They are:
boolean,byte,character,double,float,integer,long,short,true_false, andyes_no. The last two are alternate ways to represent a Boolean value within the database;true_falseuses the values “T” and “F,” whereasyes_nouses “Y” and “N.”- String type
The Hibernate type
stringmaps fromjava.lang.Stringto the appropriate string column type for the SQL dialect (usuallyVARCHAR, but in OracleVARCHAR2is used).- Time types
Hibernate uses
date,time, andtimestampto map fromjava.util.Date(and subclasses) to appropriate SQL types (e.g.,DATE,TIME,TIMESTAMP). Thetimestampimplementation uses the current time within the Java environment; you can use the database’s notion of the current time instead by usingdbtimestamp.If you prefer working with the more convenient
java.util.Calendarclass, there is no need to translate to and fromDatevalues in your own code; you can map it directly withcalendar(which stores the date and time as aTIMESTAMP) orcalendar_date(which considers only the date, as aDATEcolumn).- Arbitrary precision numeric
The Hibernate type
big_decimalprovides a mapping betweenjava.math.BigDecimalto the appropriate SQL type (usuallyNUMERIC, but Oracle usesNUMBER). Hibernate’sbig_integermapsjava.math.BigInteger(usually toBIGINT, but Informix calls itINT8and Oracle again usesNUMBER).- Localization values
The types
locale,timezone, andcurrencyare stored as strings (VARCHARorVARCHAR2, as noted above), and mapped to theLocale,TimeZone, andCurrencyclasses in the java.util package.LocaleandCurrencyare stored using their ISO codes, whileTimeZoneis stored using its ID property.- Class names
The type
classmaps instances ofjava.lang.Classusing their fully qualified names, stored in a string column (VARCHAR, orVARCHAR2in Oracle).- Byte arrays
The type
binarystores byte arrays in an appropriate SQL binary type.- Any serializable object
The type
serializablecan be used to map any serializable Java object into a SQL binary column. This is the fallback type used when attempting to persist an object that doesn’t have a more specific appropriate mapping (and for which you do not want to implement aUserTypecustom mapping; see the next section). The SQL column type is the same as is used forbinary, described later.- JDBC large objects
The types
blobandclobprovide mappings for theBlobandClobclasses in the java.sql package. If you are dealing with truly large values, your best bet is to declare the properties as eitherBloborClob—even though this introduces an explicit JDBC dependency to your data object, it easily allows Hibernate to leverage JDBC features to lazily load the property value only if you need it.If you are not worried that the data is too huge, you can spare yourself this direct JDBC interface, declare the property type as
Stringorbyte[ ], and map it usingtextorbinary. These correspond to SQL column types ofCLOBandVARBINARY(RAWin Oracle,BYTEAin PostgreSQL), respectively, and the values are loaded immediately into the properties when the object is loaded.
In addition to mapping your objects as entities, you can also create classes that are mapped to the database as values within other entities, without their own independent existence. This can be as simple as changing the way an existing type is mapped (because you want to use a different column type or representation), or as complex as splitting a value across multiple columns.
Although you can do this on a case-by-case basis within your mapping
documents, the principle of avoiding repeated code argues for
encapsulating types you use in more than one place into an actual reusable
class. Your class will implement either org.hibernate.UserType or org.hibernate.CompositeUserType. This
technique is illustrated in Chapter 6.
This is also how you map Java 5’s enum types (and
hand-coded instances of the type-safe enumeration pattern in from previous
Java versions). You can use a single, reusable custom type mapping for all
enumerations, as discussed in Chapter 6.
This final kind of mapping is very much a free-for-all. Essentially, it allows you to map references to any of your other mapped entities interchangeably. This is done by providing two columns, one which contains the name of the table to which each reference is being made, and another which provides the ID within that table of the specific entity of interest.
You can’t maintain any sort of foreign key constraints in such a loose relationship. It’s rare to need this kind of mapping at all. One situation in which you might find it useful is if you want to maintain an audit log that can contain actual objects. The reference manual also mentions web application session data as another potential use, but that seems unlikely in a well-structured application.
The following table shows each of the type classes in the
org.hibernate.types package, along with the type name
you would use for it in a mapping document, the most common SQL type(s) used in columns storing
mapped values, and any relevant comments about its purpose. In many cases,
more detailed discussion can be found earlier. To save space, the
“Type” that appears at the end of each
class name has been removed, except in the case of the
Type interface implemented by all the
others.
There is also a TypeFactory class which provides assistance in building the right
Type implementation for a given need, such as when
parsing a type name in a mapping document. Reading its source is
interesting.
If you enjoyed this excerpt, buy a copy of Harnessing Hibernate .
