Java Persistence/Basic Attributes

=Basics= A basic attribute is one where the attribute class is a simple type such as,  ,   or a primitive. A basic attribute's value can map directly to the column value in the database. The following table summarizes the basic types and the database types they map to.

In JPA a basic attribute is mapped through the annotation or the   element. The types and conversions supported depend on the JPA implementation and database platform. Some JPA implementations may support conversion between many different data-types or additional types, or have extended type conversion support, see the advanced section for more details. Any basic attribute using a type that does not map directly to a database type can be serialized to a binary database type.

The easiest way to map a basic attribute in JPA is to do nothing. Any attributes that have no other annotations and do not reference other entities will be automatically mapped as basic, and even serialized if not a basic type. The column name for the attribute will be defaulted, named the same as the attribute name, as uppercase. Sometimes auto-mapping can be unexpected if you have an attribute in your class that you did not intend to have persisted. You must mark any such non-persistent fields using the annotation or   element.

Although auto-mapping makes rapid prototyping easy, you typically reach a point where you want control over your database schema. To specify the column name for a basic attribute the annotation or   element is used. The column annotation also allows for other information to be specified such as the database type, size, and some constraints.

Translating Values

 * See Conversion

Truncated Data

 * A common issue is that data, such as Strings, written from the object are truncated when read back from the database. This is normally caused by the column length not being large enough to handle the object's data.  In Java there is no maximum size for a String, but in a database   field, there is a maximum size.  You must ensure that the length you set in your column when you create the table is large enough to handle any object value.  For very large Strings  s can be used, but in general  s should not be over used, as they are less efficient than a.


 * If you use JPA to generate your database schema, you can set the column length through the  annotation or element, see Column Definition and Schema Generation.

How to map timestamp with timezones?

 * See Timezones

How to map XML data-types?

 * See Custom Types

How to map Struct and Array types?

 * See Custom Types

How to map custom database types?

 * See Custom Types

How to exclude fields from INSERT or UPDATE statements, or default values in triggers?

 * See Insertable, Updatable

=Advanced=

Temporal, Dates, Times, Timestamps and Calendars
Dates, times, and timestamps are common types both in the database and in Java, so in theory mappings these types should be simple, right? Well sometimes this is the case and just a normal  mapping can be used, however sometimes it becomes more complex.

Some databases do not have  and   types, only   fields, however some do have separate types, and some just have   and. Originally in Java 1.0, Java only had a  type, which was both a date, time and milliseconds. In Java 1.1 this was expanded to support the common database types with,  , and  , then to support internationalization Java created the   type and virtually deprecated (almost all of the methods) the old date types (which JDBC still uses).

If you map a Java  type to a database , this is just a basic mapping and you should not have any issues (ignore Oracle's   type that is/was a timestamp for now). You can also map  to , and   to. However if you have a  or   in Java and wish to map it to a   or , you may need to indicate that the JPA provider perform some sort of conversion for this. In JPA the annotation or   element is used to map this. You can indicate that just the  or   portion of the date/time value be stored to the database. You could also use  to map a   to a   field, or any other such conversion.

Milliseconds
The precision of milliseconds is different for different temporal classes and database types, and on different databases. The  and   classes support milliseconds. The  and   classes do not support milliseconds. The  class supports nanoseconds.

On many databases the  type supports milliseconds. On Oracle prior to Oracle 9, there was only a  type, which was a date and a time, but had no milliseconds. Oracle 9 added a  type that has milliseconds (and nanoseconds), and now treats the old   type as only a date, so be careful using it as a timestamp. MySQL has,   and   types. DB2 has a,   and   types, the   supports microseconds. Sybase and SQL Server just have a  type which has milliseconds, but at least on some versions has precision issues, it seems to store an estimate of the milliseconds, not the exact value.

If you use timestamp version locking you need to be very careful of your milliseconds precision. Ensure your database supports milliseconds precisely otherwise you may have issues, especially if the value is assigned in Java, then differs what gets stored on the database, which will cause the next update to fail for the same object.

In general I would not recommend using a timestamp and as primary key or for version locking. There are too many database compatibility issues, as well as the obvious issue of not supporting two operations in the same millisecond.

Timezones
Temporals become a lot more complex when you start to consider time zones, internationalization, eras, locals, day-light savings time, etc. In Java only  supports time zones. Normally a  is assumed to be in the local time zone, and is stored and retrieved from the database with that assumption. If you then read that same  on another computer in another time zone, the question is if you will have the same   or will you have the   of what the original time would have been in the new time zone? It depends on if the  is stored as the GMT time, or the local time, and if the time zone was stored in the database.

Some databases support time zones, but most database types do not store the time zone. Oracle has two special types for timestamps with time zones,  (time zone is stored) and   (local time zone is used). Some JPA providers may have extended support for storing  objects and time zones.


 * TopLink, EclipseLink : Support the Oracle  and   types using the   annotation and XML.

Forum Posts
 * Investigation of storing timezones in MySQL

Joda-Time
Joda-Time is a commonly used framework for date/time usage in Java. It replaces Java Calendars which many people find difficult to use and have poor performance. There is no standard Joda-Time support in JPA, but a  can be used to convert from Joda-Time classes and database types.


 * TopLink, EclipseLink : The base product offers no specific Joda-Time support, but there is a custom converter provided by a third party library, joda-time-eclipselink-integration.

Enums
Java are typically used as constants in an object model. For example an  may have a   of enum type.

By default in JPA an attribute of type Enum will be stored as a  to the database, using the integer Enum values as codes (i.e. ,  ). JPA also defines an @Enumerated annotation and  element (on a  ) to define an Enum attribute. This can be used to store the Enum as the  value of its name (i.e. ,  ).

For translating Enum types to values other than the integer or String name, such as character constants, see Translating Values.

LOBs, BLOBs, CLOBs and Serialization
A  is a Large OBject, such as a   (Binary LOB), or a   (Character LOB). It is a database type that can store a large binary or string value, as the normal  or   types typically have size limitations. A LOB is often stored as a locator in the database table, with the actual data stored outside of the table. In Java a  will normally map to a , and a   will normally map to a  , although a   may also represent some serialized object.

By default in JPA any  attribute that is not a relationship or a basic type (String, Number, temporal, primitive), will be serialized to a   field.

JPA defines the @Lob annotation and  element (on a  ) to define that an attribute maps to a   type in the database. The annotation is just a hint to the JPA implementation that this attribute will be stored in a LOB, as LOBs may need to be persisted specially. Sometimes just mapping the LOB as a normal  will work fine as well.

Various databases and JDBC drivers have various limits for LOB sizes. Some JDBC drivers have issues beyond 4k, 32k or 1meg. The Oracle thin JDBC drivers had a 4k limitation in some versions for binding LOB data. Oracle provided a workaround for this limitation, which some JPA providers support. For reading LOBs, some JDBC drivers prefer using streams, some JPA providers also support this option.

Typically the entire LOB will be read and written for the attribute. For very large LOBs reading the value always, or reading the entire value may not be desired. The fetch type of the  could be set to   to avoid reading a LOB unless accessed. Support for  fetching on   is optional in JPA, so some JPA providers may not support it. A workaround, which is often a good idea in general given the large performance cost of LOBs, is to store the LOB in a separate table and class and define a  to the LOB object instead of a. If the entire LOB is never desired to be read, then it should not be mapped. It is best to use direct JDBC to access and stream the LOB in this case. It may be possible to map the LOB to a /  in your object to avoid reading the entire LOB, but these require a live connection, so may have issues with detached objects.

Lazy Fetching
The  attribute can be set on a   mapping to use   fetching. By default all  mappings are , which means the column is selected whenever the object is selected. By setting the  to , the column will not be selected with the object. If the attribute is accessed, then the attribute value will be selected in a separate database select. Support for  is an optional feature of JPA, so some JPA providers may not support it. Typically support for lazy on basics will require some form of byte code weaving, or dynamic byte code generation, which may have issues in certain environments or JVMs, or may require preprocessing your application's persistence unit jar.

Only attributes that are rarely accessed should be marked lazy, as accessing the attribute causes a separate database select, which can hurt performance. This is especially true if a large number of objects is queried. The original query will require one database select, but if each object's lazy attribute is accessed, this will require  database selects, which can be a major performance issue.

Using lazy fetching on basics is similar to the concept of fetch groups. Lazy basics is basically support for a single default fetch group. Some JPA providers support fetch groups in general, which allow more sophisticated control over what attributes are fetched per query.


 * TopLink, EclipseLink : Support lazy basics and fetch groups. Fetch groups can be configured through the EclipseLink API using the   class.

Optional
A  attribute can be   if its value is allowed to be null. By default everything is assumed to be optional, except for an, which can not be optional. Optional is basically only a hint that applies to database schema generation, if the persistence provider is configured to generate the schema. It adds a  constraint to the column if. Some JPA providers also perform validation of the object for optional attributes, and will throw a validation error before writing to the database, but this is not required by the JPA specification. Optional is defined through the  attribute of the   annotation or element.

Column Definition and Schema Generation
There are various attributes on the annotation and element for database schema generation. If you do not use JPA to generate your schema you can ignore these. Many JPA providers do provide the feature of auto generation of the database schema. By default the Java types of the object's attributes are mapped to their corresponding database type for the database platform you are using. You may require configuring your database platform with your provider (such as a persistence.xml property) to allow schema generation for your database, as many database use different type names.

The  attribute of   can be used to override the default database type used, or enhance the type definition with constraints or other such DDL. The,   and   can also be set to override defaults. Since the defaults for the  are just defaults, it is normally a good idea to set these to be correct for your data model's expected data, to avoid data truncation. The  attribute can be used to define a unique constraint on the column, most JPA providers will automatically define primary key and foreign key constraints based on the   and relationship mappings.

JPA does not define any options to define an index. Some JPA providers may provide extensions for this. You can also create your own indexes through native queries

Example of column XML
If using BigDecimal with Postgresql, JPA maps salary to a table column of type NUMERIC(38,0). You can adjust scale and precision for BigDecimal within the @Column annotation.

Insertable, Updatable / Read Only Fields / Returning
The  annotation and XML element defines   and   options. These allow for this column, or foreign key field to be omitted from the SQL INSERT or UPDATE statement. These can be used if constraints on the table prevent insert or update operations. They can also be used if multiple attributes map to the same database column, such as with a foreign key field through a  and   or   mapping. Setting both  and   to false, effectively mark the attribute as read-only.

and  can also be used in the database table defaults, or auto assigns values to the column on insert or update. Be careful in doing this though, as this means that the object's values will be out of synch with the database, unless it is refreshed. For  or auto assigned id columns a   should normally be used, instead of setting   to false. Some JPA providers also support returning auto assigned fields values from the database after insert or update operations. The cost of refreshing or returning fields back into the object can affect performance, so it is normally better to initialize field values in the object model, not in the database.


 * TopLink, EclipseLink : Support returning insert and update values back into the object using the  and   annotations and XML elements.

Converters (JPA 2.1)
A common problem in storing values to the database is that the value desired in Java differs from the value used in the database. Common examples include using a  in Java and a ,   or a  ,   in the database. Other examples are using a  in Java and a   in the database, or mapping custom Java types such as Joda-Time types, or a Money type.

JPA 2.1 defines the,   annotations and  ,   XML elements. A  is a user defined class that provides custom conversion routines in Java code. It must implement the  interface and be annotated with the   annotation (or specified in XML). A  can be used in one of two ways. Normally it is specified on a mapping using the  annotation or   XML element. Another option, if converting a custom type, is to have the  applied to any mapped attribute that has that type. To define such as global converter the  flag is added to the   annotation. The    flag can be used to disable a global converter from being applied. The    option can be used to override inherited or embeddable conversions.

Conversion
Previous to JPA 2.1 there was no standard way to convert between a data-type and an object-type. One way to accomplish this was to translate the data through property get/set methods.

Also for translating date/times see, Temporals.

As well some JPA providers have special conversion support.


 * TopLink, EclipseLink : Support translation using the,  ,   and   annotations and XML.

Custom Types
JPA defines support for most common database types, however some databases and JDBC driver have additional types that may require additional support.

Some custom database types include:
 * TIMESTAMPTZ, TIMESTAMPLTZ (Oracle)
 * TIMESTAMP WITH TIMEZONE (Postgres)
 * XMLTYPE (Oracle)
 * XML (DB2)
 * NCHAR, NVARCHAR, NCLOB (Oracle)
 * Struct (STRUCT Oracle)
 * Array (VARRAY Oracle)
 * BINARY_INTEGER, DEC, INT, NATURAL, NATURALN, BOOLEAN (Oracle)
 * POSITIVE, POSITIVEN, SIGNTYPE, PLS_INTEGER (Oracle)
 * RECORD, TABLE (Oracle)
 * SDO_GEOMETRY (Oracle)
 * LOBs (Oracle thin driver)

To handle persistence to custom database types you may be able to use a  or special feature of your JPA provider. Otherwise you may need to mix raw JDBC code with your JPA objects. Some JPA providers provide custom support for many custom database types, some also provide custom hooks for adding your own JDBC code to support a custom database type.


 * TopLink, EclipseLink : Support several custom database types including, TIMESTAMPTZ, TIMESTAMPLTZ, XMLTYPE, NCHAR, NVARCHAR, NCLOB, object-relational Struct and Array types, PLSQL types, SDO_GEOMETRY and LOBs.

Basic Attributes