Wednesday, 26 September 2012

Hibernate Types

Hibernate makes a fundamental distinction between two different kinds of data in terms of how they relate to the persistence service: entities and values.

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, and 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.


A.1 Basic Types
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, and yes_no. The last two are alternate ways to represent a Boolean value within the database; true_false uses the values 'T' and 'F', while yes_no uses 'Y' and 'N'.




String type

The Hibernate type string maps from java.lang.String to the appropriate string column type for the SQL dialect (usually VARCHAR, but in Oracle VARCHAR2 is used).




Time types

Hibernate uses date, time, and timestamp to map from java.util.Date (and subclasses) to appropriate SQL types (e.g., DATE, TIME, TIMESTAMP).




Arbitrary precision numeric

The Hibernate type big_decimal provides a mapping between java.math.BigDecimal to the appropriate SQL type (usually NUMERIC, but Oracle uses NUMBER).




Localization values

The types locale, timezone, and currency are stored as strings (VARCHAR or VARCHAR2 as noted above), and mapped to the Locale, TimeZone, and Currency classes in the java.util package. Locale and Currency are stored using their ISO codes, while TimeZone is stored using its ID property.




Class names

The type class maps instances of java.lang.Class using their fully qualified names, stored in a string column (VARCHAR, or VARCHAR2 in Oracle).




Byte arrays

The type binary stores byte arrays in an appropriate SQL binary type.




Any serializable object

The type serializable can 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 does not implement PersistentEnum; see the next section).




JDBC large objects

The types blob and clob provide mappings for the Blob and Clob classes in the java.sql package. Note that there are rather severe restrictions on using these classes. Driver support is rather inconsistent in the first place, and they can't be reused past a single transaction.



A.2 Persistent Enumerated Types
Hibernate provides a mechanism to help map the common Java type-safe enumeration pattern to a database column. Unfortunately, the approach taken requires your enumerations to have an integer representation to store in the database, forcing them back to the lowest common denominator semantics of the enum type in the C language. I hope that a richer, string-based storage mechanism will eventually be supported, to dovetail nicely with the built-in support for this idiom that is coming in Tiger (Java Version 1.5). Storing enumerations as strings would also make them more readable to users of the raw database, a form of self-documenting storage.

To work with the current Hibernate implementation, your enumeration classes need only implement the net.sf.hibernate.PersistentEnum interface, and its fromInt() and toInt() methods.


A.3 Custom Value Types
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 net.sf.hibernate.UserType or net.sf.hibernate.CompositeUserType.


A.4 'Any' Type Mappings
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.


A.5 All Types
The following table shows each of the type classes in the net.sf.hibernate.types package, along with the type name you would use for it in a mapping document, the SQL type 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' which 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.

No comments:

Post a Comment