Java Persistence API

Basics

Entities may either use persistent fields or persistent properties. If the mapping annotations are applied to the entity’s instance variables, the entity uses persistent fields. If the mapping annotations are applied to the entity’s getter methods for JavaBeans-style properties, the entity uses persistent properties. You cannot apply mapping annotations to both fields and properties in a single entity.

Entities support class inheritance, polymorphic associations, and polymorphic queries. They can extend non-entity classes, and non-entity classes can extend entity classes. Entity classes can be both abstract and concrete. Abstract entities can not be instantiated but can be queried.

@MappedSuperclass
public class BaseEnt {//does not have a table but contains state and mapping info.
    @Id
    protected Integer id;
    ...
}
 
@Entity
public class FullTimeEmployee extends Employee {
    protected Integer salary;
    ...
}

A persistence context is a set of managed entity instances that exist in a particular data store. The EntityManager interacts with the persistence context.

Entities are managed by the entity manager. Each EntityManager instance is associated
with a persistence context. A persistence context defines the scope under which particular entity instances are created, persisted, and removed.

The EntityManager can be container or application managed.
The Java EE container manages the life cycle of container-managed entity managers.
To obtain an EntityManager instance, inject the entity manager into the application component:

@PersistenceContext
EntityManager em;

In case of application managed, to obtain an EntityManager, we should use: EntityManagerFactory:

@PersistenceUnit
EntityManagerFactory emf;
EntityManager em = emf.createEntityManager();

A persistence unit (defined by the persistence.xml) defines a set of all entity classes that are managed by EntityManager instances in an application.

<persistence>
     <persistence-unit name="OrderManagement">
                          <jta-data-source>jdbc/MyOrderDB</jta-data-source>
                          <jar-file>MyOrderApp.jar</jar-file>
                          <class>com.widgets.Order</class>
                          <class>com.widgets.Customer</class>
      </persistence-unit>
</persistence>

Entities

@Entity
@Table(name="WEB_BOOKSTORE_BOOKS") //we use this when the table name is different from entity name
public class Book implements Serializable {
 
     private String bookId;
     private String title;
 
     public Book() { }
 
     public Book(String bookId, String title, ...) {
          this.bookId = bookId;
          this.title = title;
     }
 
     @Id
     public String getBookId() {
          return this.bookId;
     }
 
     public void setBookId(String id) {
          this.bookId=id;
     }
 
      public String getTitle() {
           return this.title;
      }
 
      public void setTitle(String title) {
           this.title=title;
      }
}

EntityManager in Web Applications

Resource injection using annotations can only be used with classes that are managed by a Java EE compliant container. Because the web
container does not manage JavaBeans components, you cannot inject resources into them. One exception is a request-scoped JSF managed bean.
You can still use resource injection in a web application if you can do it in an object that is managed by the container. These objects include
servlets and ServletContextListener objects. These objects can then give the application’s beans access to the resources.

Also keep in mind that EntityManagerFactory is thread-safe but persistence context is not.

Check bookstore examples.

Mapping Strategies

A single table per class hierarchy
This strategy provides good support for polymorphic relationships but it requires the columns that contain the state of subclasses to be nullable.

A table per concrete entity class
This strategy provides poor support for polymorphic relationships, and usually requires either SQL UNION queries or separate SQL queries for each subclass for queries that cover the entire entity class hierarchy. Support for this strategy is optional,

Join strategy
Fields or properties that are specific to a subclass are mapped to a different table than the fields or properties that are common to the parent class. This strategy provides good support for polymorphic relationships but has some performance problems.

Multiplicity in Entity Relationships

There are four types of multiplicities: one-to-one, one-to-many, many-to-one, and many-to-many.

Direction in Entity Relationships

The direction of a relationship can be either bidirectional or unidirectional. A bidirectional relationship has both an owning side and an inverse side. A unidirectional relationship has only an owning side. The owning side of a relationship determines how the Persistence runtime makes updates to the relationship in the database.

Bidirectional Relationships

In a bidirectional relationship, each entity has a relationship field or property that refers to the other entity. Through the relationship field or property, an entity class’s code can access its related object. If an entity has a related field, then the entity is said to “know” about its related object. For example, if Order knows what LineItem instances it has and if LineItem knows what Order it belongs to, then they have a bidirectional relationship.

Bidirectional relationships must follow these rules:

  • The inverse (non-owning) side of a bidirectional relationship must refer to its owning side by using the mappedBy element of the @OneToOne, @OneToMany, or @ManyToMany annotation. The mappedBy element designates the property or field in the entity that is the owner of the relationship.
  • The many side of many-to-one bidirectional relationships must not define the mappedBy element. The many side is always the owning side of the relationship.
  • For one-to-one bidirectional relationships, the owning side corresponds to the side that contains the corresponding foreign key. the non-owning side is marked by the mappedBy element in the relationship annotation.
  • For many-to-many bidirectional relationships either side may be the owning side.
  • Both sides have annotation.

Unidirectional Relationships

In a unidirectional relationship, only one entity has a relationship field or property that refers to the other. For example, LineItem would have a relationship field that identifies Product, but Product would not have a relationship field or property for LineItem. In other words, LineItem knows about Product, but Product doesn’t know which LineItem instances refer to it. The owner side should use the annotation.

Example 1

From Roster example of JEE tutorial.
Because the relationship between Player (inverse, or non-owning side) and Team is bidirectional, the choice of which entity is the owner of the relationship is arbitrary.

Player(m) - Team(m), Bidirectional
Team(m) - League(1), Bidirectional

public Class Team {
    @ManyToMany
    @JoinTable(name = "EJB_ROSTER_TEAM_PLAYER", joinColumns = @JoinColumn(name = "TEAM_ID", referencedColumnName = "ID")
    , inverseJoinColumns = @JoinColumn(name = "PLAYER_ID", referencedColumnName = "ID")
    )
    public Collection<Player> getPlayers() {
        return players;
    }
 
    @ManyToOne
    public League getLeague() {
        return league;
    }
}
 
public class League{
    @OneToMany(cascade = ALL, mappedBy = "league")
    public Collection<Team> getTeams() {
        return teams;
    }
}
 
public class Player{
    @ManyToMany(mappedBy = "players")
    public Collection<Team> getTeams() {
        return teams;
    }
}

Example 2

From Order example of JEE tutorial.
Order(1) - LineItem(m), Bidirectional

public classOrder{
    @OneToMany(cascade=ALL, mappedBy="order")
    public Collection<LineItem> getLineItems() {
        return lineItems;
    }
}
 
public class LineItem{
    @ManyToOne
        public Order getOrder() {
        return order;
    }
}

Example 3

Self referencing, unidrectional object:

public class Message {
    @Id @GeneratedValue
    private Long id;
 
    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "NEXT_MESSAGE_ID")
    private Message nextMessage
}

If we need a bidirectional relationship then we add private Category parentMessage; as well.

Another self referencing relation:

@ManyToOne
public Part getMasterPart() {
    return masterPart;
}
...
@OneToMany(mappedBy="masterPart")
public Collection<Part> getParts() {
    return parts;
}
page_revision: 26, last_edited: 1223617446|%e %b %Y, %H:%M %Z (%O ago)
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License