Java Persistence/Mapping
From Wikibooks, the open-content textbooks collection
Contents |
[edit] Mapping
The first thing that you need to do to persist something in Java is define how it is to be persisted. This is called the mapping process (details). There have been many different solutions to the mapping process over the years, including some object-databases that didn't require you map anything, just lets you persist anything directly. Object-relational mapping tools that would generate an object model for a data model that included the mapping and persistence logic in it. ORM products that provided mapping tools to allow the mapping of an existing object model to an existing data model and stored this mapping meta-data in flat files, database tables, XML and finally annotations.
In JPA mappings can either be stored through Java annotations, or in XML files. One significant aspect of JPA is that only the minimal amount of mapping is required. JPA implementations are required to provide defaults for almost all aspects of mapping and object.
The minimum requirement to mapping an object in JPA is to define which objects can be persisted. This is done through either marking the class with the @Entity annotation, or adding an <entity> tag for the class in the persistence unit's ORM XML file. Also the primary key, or unique identifier attribute(s) must be defined for the class. This is done through marking one of the class' fields or properties (get method) with the @Id annotation, or adding an <id> tag for the class' attribute in the ORM XML file.
The JPA implementation will default all other mapping information, including defaulting the table name, column names for all defined fields or properties, cardinality and mapping of relationships, all SQL and persistence logic for accessing the objects. Most JPA implementations also provide the option of generating the database tables at runtime, so very little work is required by the developer to rapidly develop a persistent JPA application.
[edit] Example object model
[edit] Example data model
[edit] Example of a persistent entity mappings in annotations
import javax.persistence.*; ... @Entity public class Employee { @Id private long id; private String firstName; private String lastName; private Address address; private List<Phone> phones; private Employee manager; private List<Employee> managedEmployees; ... }
[edit] Example of a persistent entity mappings in XML
<?xml version="1.0" encoding="UTF-8"?> <entity-mappings version="1.0" xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"> <description>The minimal mappings for a persistent entity in XML.</description> <entity name="Employee" class="org.acme.Employee" access="FIELD"> <attributes> <id name="id"/> </attributes> </entity> </entity-mappings>
[edit] Common Problems
[edit] My annotations are ignored
- This typically occurs when you annotate both the fields and methods (properties) of the class. You must choose either field or property access, and be consistent. Also when annotating properties you must put the annotation on the get method, not the set method. Also ensure that you have not defined the same mappings in XML, which may be overriding the annotations. You may also have a classpath issue, such as having an old version of the class on the classpath.
[edit] Odd behavior
- There are many reasons that odd behavior can occur with persistence. One common issue that can cause odd behavior is using property access and putting side effects in your get or set methods. For this reason it is generally recommended to use field access in mapping, i.e. putting your annotations on your variables not your get methods.
- For example consider:
public void setPhones(List<Phone> phones) { for (Phone phone : phones) { phone.setOwner(this); } this.phones = phones; }
- This may look innocent, but these side effects can have unexpected consequences. For example if the relationship was
lazythis would have the effect of always instantiating the collection when set from the database. It could also have consequences with certain JPA implementations for persisting, merging and other operations, causing duplicate inserts, missed updates, or a corrupt object model.
- I have also seen simply incorrect property methods, such as a get method that always returns a new object, or a copy, or set methods that don't actually set the value.
- In general if you are going to use property access, ensure your property methods are free of side effects. Perhaps even use different property methods than your application uses.