JPA Class Mapping

When persisting a class you need to decide how it is to be mapped to the datastore. By this we mean which fields of the class are persisted. DataNucleus knows how to persist certain Java types and so you bear this list in mind when deciding which fields to persist. Also please note that JPA cannot persist static or final fields . Let's take a sample class as an example

public class Hotel
{
    private long id; // identity
    private String name;
    private String address;
    private String telephoneNumber;
    private int numberOfRooms;
    private String hotelNickname;
    private Set rooms = new HashSet();
    private Manager manager;
    ...
}

We have a series of fields and we want to persist all fields apart from hotelNickname which is of no real use in our system. In addition, we want our Hotel class to be detachable, meaning that we can detach objects of that type update them in a different part of our system, and the attach them again.

We can define this basic persistence information in 3 ways - with XML MetaData, with JDK1.5 Annotations or with a mix of MetaData and Annotations. We show all ways here.

MetaData

To achieve the above aim we define our Meta-Data like this

<entity class="org.datanucleus.test.Hotel">
    <attributes>
        <id name="id"/>
        <basic name="name"/>
        <basic name="address"/>
        <basic name="telephoneNumber"/>
        <basic name="numberOfRooms"/>
        <transient name="hotelNickname"/>
        <one-to-many name="rooms" target-entity="org.datanucleus.test.Room"/>
        <one-to-one name="manager" target-entity="org.datanucleus.test.Manager"/>
    </attributes>
</entity>

Note the following

  • We have identified our id field as the identity. We didnt bother specifying an Primary key class since we only have a single PK field
  • We have included all fields in the MetaData, although if you look at the Types Guide you see the column "Persistent?". All "simple" types like String, int are by default persistent and so we could have omitted these since they are by default going to be persisted.
  • We have used transient for the hotelNickname field to make it non-persistent.
  • Our Set field we have identified as "1-N" and the type of the element that it contains. This is compulsory for collection and map fields (unless using JDK1.5 generics).
  • We have identified our manager field as "1-1"

So it is really very simple. This first step is to define the basic persistence of a class. If you are using a datastore (such as RDBMS) that requires detailed mapping information then you now need to proceed to the JPA Schema Mapping Guide. If however you are using a datastore that doesn't need such information (such as DB4O) then you have defined the persistence of your class.

See also :-



Annotations

Here we are using JDK1.5 or higher and we annotate the class directly using JPA Annotations We annotate the class like this

@Entity
public class Hotel
{
    @Id
    private long id;

    @Basic
    private String name;

    @Basic
    private String address;

    @Basic
    private String telephoneNumber;

    @Basic
    private int numberOfRooms;

    @Transient
    private String hotelNickname;

    @OneToMany(target="Room")
    private Set rooms = new HashSet();

    @OneToOne(target="Manager)
    private Manager manager;
    ...
}
                

See also :-



Annotations + MetaData

If we are using JDK 1.5+ we can take advantage of Annotations, but we want to take into account the disadvantage of Annotations, namely that we may want to deploy our application to multiple datastores. This means that we would be extremely unwise to specify ORM information in Annotations. With this in mind we decide that we will specify just the basic persistence information (which classes/fields are persisted etc) using Annotations, and the remainder will go in MetaData.

The order of precedence for persistence information is

  • JPA MetaData definition
  • Annotations definition

So anything specified in MetaData will override all Annotations.

Persistence Aware

With JPA you cannot access public fields of classes. DataNucleus allows an extension to permit this, but such classes need special enhancement. To allow this you need to

  • Annotate the class that will access these public fields (assuming it isn't an Entity) with the DataNucleus extension annotation @PersistenceAware
  • At runtime set the persistence property datanucleus.jpa.level to DataNucleus
You perform the annotation of the class as follows

@PersistenceAware
public class MyClassThatAccessesPublicFields
{
    ...
}

See also :-