2 Annotating Entities

Our sample application My Campaign enables organizers of charitable campaigns to create online donation forms for their projects.
During the design of the application, we defined several entity classes (see domain classes of My Campaign). Currently, our application possesses only the entities Donation and Campaign. The dependent entity Account has a special role and will not be dealt with at this stage.

To enable JPA to manage the entities, various annotations – as described in the following sections – must be added to the classes. An alternative method (without annotations) would be to create a configuration file for defining the object-relational mapping; however, this approach will not be used in our application.

It should also be mentioned that JPA supports the inheritance of entities. There are a number of different strategies for mapping the class hierarchy to the relational model of the database. The default strategy is to use one table per class hierarchy and to store the exact type in an additional column. Since inheritance is not used in our sample application, we won’t go any further into the different strategies here; if interested, you can find more details in e.g. (Keith, 2014) or
(Bauer, 2015).

2.1 Project Setup

You can continue with your final project after working off the chapter 5 of the Cloud Tutorial CDI in a Day. If you have already closed it or you are just beginning with JPA, you can start a temporary session by clicking the following link. Don’t forget that the whole work is volatile unless you sign up to Codenvy and persist the project in your own workspace.

Start Cloud IDE

Start Cloud IDE

2.2 Marking as an Entity and Defining a Primary Key

Firstly, each of the classes that we wish to be managed as entities by JPA should be annotated as such using @Entity from the package javax.persistence. To begin with, we add the annotation only for the classes Donation and Campaign contained in the package press.turngeek.mycampaign.model:

@Entity                                      
public class Donation {
…

and

@Entity
public class Campaign {
…

Since each entity requires a primary key in order to be uniquely identified, we will now create primary keys for the classes Campaign und Donation.

To accomplish this, we will first add an attribute id to the class Donation and annotate the attribute with @Id und @GeneratedValue (both from the package javax.persistence):

@GeneratedValue
@Id
private Long id;

The annotation @Id indicates that the attribute is a primary key. @GeneratedValue causes the value of the primary key to be generated by JPA and saves the developer the trouble of generating a unique identity themselves.

Strategies for Primary Key Generation

JPA supports various strategies for the generation of a primary key. GenerationType.AUTO is used by convention and prompts the JPA implementation to automatically select the most compatible strategy for the underlying database. GenerationType.TABLE, GenerationType.SEQUENCE and GenerationType.IDENTITY can all be used as alternatives. In the first case, the identity is implemented via a table with incremental value; in the second, it is implemented via a database sequence and in the third, via an identity function belonging to the database. The strategy can be modified using the strategy parameter of the @GeneratedValue annotation.

Next, we will create a getter and setter method for the new attribute of the primary key:

public Long getId() {
   return id;
}

public void setId(Long id) {
   this.id = id;
}

Back in the JSF chapter, we created an attribute with the name id and type Long for the Campaign class. We can convert this into a primary key by simply adding the annotations @GeneratedValue and @Id.

This results in the following definition:

@GeneratedValue
@Id
private Long id;

After we have marked the classes as entities and generated primary keys, we can persist the classes using the EntityManager as described earlier.

Note that JPA only persists attributes of the following types:

  • primitive data types and strings
  • serializable types (implements java.io.Serializable)
  • enumerations
  • other entities or lists of entities
  • classes annotated with @Embeddable (see section 2.4)

If an attribute falls into one of the above categories and we do not wish to persist it, we must annotate it with @Transient from the package javax.persistence. This functionality will be required later in our sample application.

2.3 Defining Relationships Between Entities

Objects in a database can be in relationships with other objects. This allows objects of one type to be associated with another type.

In our case, there is a 1:n relation between the entities Campaign and Donation. This means that 0 to n Donation objects are associated with a Campaign object and a single Campaign object is associated with a Donation object.

We use the annotations @ManyToOne and @OneToMany (from the package javax.persistence) to define a 1:n relation in JPA. These annotations are used to annotate the attribute of the type that is to be assigned. The decision about which annotation to use depends on the direction of the relationship.

In our case, we will create a bidirectional relationship between the entities Campaign and Donation. This means that the developer will be able to access assigned instances of the other class through any of the classes involved in the relationship. In the case of a unidirectional relationship, the developer is only able to start from one of the classes.

We will start with the direction that gives us the object of type Donation that is associated with a Campaign object. To do this, the attribute with the list of objects of type Donation in the class Campaign must simply be annotated with @OneToMany:

@OneToMany
private List<Donation> donations;
…

And that’s it! This additional line defines a unidirectional 1:n relationship from the entity Campaign to the entity Donation. As a result of this relationship, each object of type Donation is uniquely related to a Campaign object. In the corresponding database table, a foreign key to the table CAMPAIGN is created in the table DONATION, so that adherence to the relationship is overeen by the database.

As you will have guessed, the relationship in the opposite direction is defined using the annotation @ManyToOne. We will therefore create an attribute with this annotation in the Donation class for the purpose of storing the assigned Campaign object:

@ManyToOne
private Campaign campaign;
…

We must also add to the class the corresponding getter and setter methods for accessing the attribute:

public Campaign getCampaign() {
   return campaign;
}

public void setCampaign(Campaign campaign) {
   this.campaign = campaign;
}

We have now created two differently complete relationships, one between Campaign and Donation and another between Donation and Campaign. Each of the relationships relates a donation to exactly one campaign. However, since we have two different relationships, it is possible for a donation to belong to two different campaigns. This is something we do not want.  Instead, our aim is to define a single bi-directional relationship between Campaign and Donation for assigning a donation to exactly one campaign.

To create a bidirectional relationship, the two attributes annotated with @ManyToOne and @OneToMany must be linked with each other. In JPA, this is controlled by the parameter mappedBy, in which the name of an attribute of the assigned class is given. This attribute must be the type of the current class. As a result, both attributes involved in the relationship form a pair.

In our sample application, we will extend the @OneToMany-Annotation in the class Campaign:

@OneToMany(mappedBy = "campaign")

private List<Donation> donations;

Our bidirectional relationship is now uniquely defined and the assigned objects can be traversed from both sides.
A 1:n relation is not the only relationship you can define using JPA. The annotation @OneToOne defines a 1:1 relation whereby an object is assigned to precisely one other object. However, this more simple case is not required in our application and will therefore not be looked at here.

JPA also allows us to define m:n relationships – for this, we need the annotation @ManyToMany. In practice, however, this annotation is scarcely ever used, since it enables a relationship to be formed between two 1:n relationships and one other connecting entity. Such a relationship has the advantage that further information can be stored in the additional entity if required.

2.4 Embedding Dependent Entities

Unlike a normal entity, a dependent entity exists only in dependence on another entity. Rahter than requiring a primary key for identification, it is identified via the entity on which it is dependent.

Account is an example of a dependent entity in our application. An account consists of the name of the name of the owner, the IBAN and the name of the bank. Since both a donation and a campaign require this information, they have each embedded the dependent entity Account instead of defining these attributes themselves. This serves the purpose of avoiding redundancies. More details on this can be found in the definition of the domain classes.

To define a dependent entity in JPA, the entity must be annotated with @Embeddable from the package javax.persistence. So, in our case:

@Embeddable
public class Account {

If a dependent entity is embedded, the attribute that stores the dependent entity must be annotated with @Embedded (also from the package javax.persistence). Thus, in our case, the account attribute must be annotated in both the Donation and the Campaign classes:

@Embedded
private Account account;

This means that the database tables of the entities Donation and Campaign each contain all three columns for the storing of account information – that is, the name of the account owner, IBAN and the name of the bank.

However, this causes a problem with the entity Campaign. Like the dependent entity Account, the Campaign entity contains the attribute name. This means that the database table to be generated by JPA must contain two name columns, which is not possible.

Our JPA implementation Hibernate would recognize the error when the application is deployed and supply the following exception:

org.hibernate.MappingException: Repeated column in mapping for entity: press.turngeek.mycampaign.model.Campaign column: name

To solve the problem, we can instrcut JPA that the name attribute of the Account entity should not be stored in the name column, but in the accountName column instead. To do this, we will annotate the account attribute in the Campaign class using the annotation @AttributeOverrides from the package javax.persistence (Hint: Codenvy might have problems to recognize nested annotations. In this case just add the import statements for @AttributeOverrides, @AttributeOverride and @Column manually.):

@AttributeOverrides({@AttributeOverride(name = "name", column = @Column(name = "accountName"))})
@Embedded
private Account account;

The annotation contains a list of annotations of the type @AttributeOverride, which specifies that the name of an attribute to be persisted in the database table should take on a different name. In our case, we want the name attribute of the dependent entity Account to be persisted in the column accountName.

Since we have only added meta data to our source code, our project should still be deployable and runnable without any change in functionalty. If you have problems with your project, please compare it with the project behind the following link:

Start Cloud IDE

My-Campaign after adding JPA Annotations

Discussion

Use the message board below to give the authors your feedback or to discuss this page’s topic with other readers (in English please!). Please don’t expect the authors to answer directly, but they might update the content of this site according to your feedback.