Entity relationships revisited

In the previous chapter, we saw that an entity can be associated with another through a relationship, which can be one-to-one, one-to-many, many-to-one, or many-to-many. Relationships under JPA are polymorphic, which means you can take advantage of object oriented inheritance, if required.

JPA requires for all relationship mapping that there is one side that is identified as the target and therefore the opposite side is the owner. The primary key of the target entity is always referenced in the mapping of entity relationships.

In Java and JPA, entity relationships are by default unidirectional, which means that it is straightforward to traverse from the master-the owning entity-to the detail-the target entity. The Java developer must explicitly supply the inverse direction in order to facilitate bidirectional entity relationships.

Relationships are defined by association of primary keys in database tables (and views) to foreign keys in other tables (and views) inside a relational database. In the owning database table, the master, there is a database column containing the foreign keys of the target database table, the detail, which defines the primary keys. Associations are defined by the possibility to traverse to individual rows of the target database table from the source database table using the foreign key to primary mapping.

The source and target entity in the relationship model how the engineer can navigate from one entity to the other.

One-to-one mapping

The one-to-one mapping relationship maps one entity directly to another entity. The annotation is @javax.persistence.OneToOne.

The property or accessor method may be further annotated with the @javax.persistence.JoinColumn to further identify the target database column that contains the primary key in the target entity.

Let us look at the full attributes of the @OneToOne annotation:

Attribute

Type

Description

Default Value

targetEntity

String

The attribute represents the entity class that is the target of the relationship. For 99% of cases, you will not have to specify this relationship explicitly, since the persistence provider should be able to find the relationship.

Implied by the declaration point on the field or property accessor

cascade

String

This attribute specifies how and when the lifecycle of the dependent entity is included in any cascade operations (CascadeType.ALL, CascadeType.PERSIST etc.)

No operations are cascaded

fetch

String

This attribute specifies how the dependent entity is retrieved in a relationship. The valid values are FetchType.EAGER and FetchType.LAZY.

FetchType.EAGER

optional

Boolean

This attribute specifies if the relationship can be null or not. The default value is true; and by setting this to false a non-null relationship must exist between the entities.

true

mappedBy

String

This attribute specifies the field or accessible property accessor for the source owning entity for bidirectional relationships.

None

orphanRemoval

Boolean

This attribute specifies how removal operation takes place when the target entity is removed from the source owning entity. If the value is set to true, then the deletion of the target from the source entity will be cascaded to the target itself.

false

We already saw some examples of one-to-one mapping in the previous chapter.

Let us examine in detail the relationship between the employee and the address:

@Entity
public class Employee implements java.io.Serializable {
    /*...*/
    
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="EMPLOYEE_ADDRESS_FK",
            referencedColumnName="ADDRESS_ID")
    private Address address;
    
    public Address getAddress() { return address; }
    public void setAddress(Address address) {
        this.address = address; }    

    /*...*/
}

We have established a one-to-one unidirectional relationship between the Employee entity and the Address entity. The owner of the relationship is Employee and this determines the navigability.

Here, we configure the relationship with the @JoinColumn annotation in order to customize the database column name EMPLOYEE_ADDRESS_FK and also to specify the reference database column name in the target entity ADDRESS_ID.

Here is a table that describes the attributes for @JoinColumn annotation.

Attribute

Type

Description

Default Value

name

String

This attribute specifies the name of the foreign key that associates to the target entity. The foreign key is in the table of the source, the owner entity.

Implied by the declaration point on the field or property accessor

referencedColumn-Name

String

This attribute specifies the name of the primary key in the target entity. The reference column is in the table of the target entity.

The same name as the target database column

unique

Boolean

This attribute specifies whether the column is unique. It is also a short cut for the @UniqueConstraint annotation for a single field.

false

nullable

Boolean

This attribute specifies if the foreign key column is nullable or not.

true

insertable

Boolean

This attribute specifies if this foreign key is included in SQL INSERT operations by the persistence provider.

true

updatable

Boolean

This attribute specifies if this foreign key is included in SQL UPDATE operations by the persistence provider.

true

columnDefinition

String

Defines an additional SQL fragment that is used in the DDL generated by the persistence provider.

None

table

String

Specifies the name of the table that contains the column.

Implied by the containing entity

foreignKey

ForeignKey

Specifies the foreign constraint for the join column.

Default constraints generated by the persistence provider

Persisting one-to-one unidirectional entities

It is easy to save one-to-one related entities using JPA. All you need are the entity beans themselves and then use a method to create the dependency, and thus the association.

Here is an example that creates and saves both Employee and Address:

@PersistenceContext EntityManager em;

public void create() {
  Employee employee = new Employee();
  Address address = new Address();
  employee.setAddress(address);
  em.persist(employee);
}

This will work because we have chosen CascadeType.ALL and thus saving the Employee entity, cascades the operation from the owning entity to the dependent entity, which is the Address.

We have chosen to allow nullable references in the relationship, and therefore we can adopt a method that removes the address from the employee record, shown as follows:

@PersistenceContext EntityManager em;
public void clearAddress( int empId ) {
  Employee employee = em.find(Employee.class, id );
  employee.setAddress( null );
  em.persist(employee);
}

Now, let us move on to the bidirectional relationship.

Bidirectional one-to-one-entities

Now let us make this one-to-one relationship between an employee and an address bidirectional. In order to achieve this, we still have to inform JPA which one of these entities is the owner of the relationship. In this case, we still want the employee entity to be owner of the address.

Here is the code to achieve a bidirectional relationship:

@Entity
public class Address implements java.io.Serializable {
    /*...*/

    @OneToOne(mappedBy="address")
    private Employee employee

    public Employee getEmployee() { return employee; }
    public void setEmployee(Employee employee) {
        this.employee = employee; }
    /*...*/
}

In the Address entity, we add a brand new field employee and annotate it with @OneToOne. Here, we supplied the inverse property mappedBy="address" in order to complete the inverse relationship.

Persisting one-to-one bidirectional entities

In Java code, persisting the bidirectional entities must always be built from both sides of the relationship. Entities in Java behave like any other Java object that has a relationship. As a developer, you are required to configure both sides of the relationship in memory.

Here is a code that creates the Employee and Address records for a bidirectional association:

@PersistenceContext EntityManager em;
public void create() {
  Employee employee = new Employee();
  Address address = new Address();
  employee.setAddress(address);
  em.persist( employee );
}

Failure to configure both sides of the relationship in bidirectional mappings can result in peculiar data management errors.

Let's move on to mapping composite foreign keys.

Composite foreign keys in a one-to-one relationship

JPA can map entities with composite keys into one-to-one relationships. For this task, we need to annotate the field or property accessor with @javax.persistence.JoinColumns, which accepts an array of @JoinColumn declarations.

Here is an example of a record, a shipping record, with a set of properties:

@Entity
public class Shipping implements Serializable{
  private long id;
  private String delivery;
  private String carrier;
  private String costCenter;
  /*...*/
}

Let's suppose we are only interested in the one-to-one relationship between the Invoice and the Shipping entities, except we only want to associate across id and costCenter.

Here is some example code, which demonstrates what we can achieve with a composite key:

@Entity
public class Invoice implements java.io.Serializable {
  /*...*/
  @ManyToOne
  @JoinColumns({
     @JoinColumn(name="SHIPPING_ID",
      referencedColumnName="ID"),
      @JoinColumn(name="COST_CENTER_REF",
      referencedColumnName="COST_CENTER") })    
  private Shipping shipping;

  public Shipping getShipping() { return shipping; }
  public void setShipping( Shipping shipping) {
    this.shipping = shipping; }
  
}

The code in the Invoice class creates a one-to-one relationship, which may be a null reference, meaning an invoice can have no shipping record at all.

JPA maps the entity Invoice into the database table called INVOICE and with the additional database columns, which are the foreign key for referencing the shipping entity, namely SHIPPING_ID and COST_CENTER.

One-to-many mapping

The one-to-many mapping relationship maps one entity directly to multiple entitles. The annotation is @javax.persistence.OneToMany. The source entity is owner of a collection of target entities.

The inverse relationship of a one-to-many is a many-to-one. By contrast to either to one-to-many or many-to-one relationships, the inverse of many-to-many relationship is itself.

Let us look at the full attributes of the @OneToMany annotation:

Attribute

Type

Description

Default Value

targetEntity

String

This optional attribute represents the entity class that is the target of the relationship. If the property is used as a raw type then the attribute must be specified.

The parameterized type of the collection when defined using Java generics

cascade

String

This attribute specifies how and when the lifecycle of the dependent entity is included in any cascade operations (CascadeType.ALL, CascadeType.PERSIST etc.)

No operations are cascaded

fetch

String

This attribute specifies how the dependent entity is retrieved in a relationship. The valid values are FetchType.EAGER and FetchType.LAZY.

FetchType.LAZY

mappedBy

String

This attribute specifies the field or accessible property accessor for the source owning entity for bidirectional relationships.

None

orphanRemoval

Boolean

This attribute specifies how a removal operation takes place when the target entity is removed from the source owning entity. If the value is set to true, then the deletion of the target from the source entity will be cascaded to the target itself.

false

Let's see an example of a one-to-many in action. Employee records can have multiple telephone numbers for work, home, fax, mobile, and so on. Here is a simple phone entity bean.

@Entity
public class Phone implements java.io.Serializable {
  @Id @Column(name="PHONE_ID") 
  private int id;
  private String type;    // home,work,main,fax
  private String interCode; // international prefix
  private String areaCode;
  private String localCode;
}

The Phone entity has a primary id, a phone type, and international, area, and local dialing codes. We assume that the application has an automatic parser for deciphering a full telephone number into its constituent dialing code parts.

Here is the Employee modified to accept a list collection of telephone entities:

@Entity
public class Employee implements java.io.Serializable {
    @Id @Column(name="EMP_ID")
 private long id;
    /*...*/
    
    @OneToMany(cascade = CascadeType.ALL)
    private List<Phone> phones;
    
    public List<Phone> getPhones() { return phones; }
    public void setPhones(List<Phone> phone) {
        this.phones = phones; }    
}

In this example, the JPA provider creates a join table linking the Employee to Phone entities, which by default is EMPLOYEE_PHONE. The table has two database columns: the first is the primary key of the Employee entity, which is called Employee_EMP_ID, and the second is the foreign key of the Phone entity, which is called Phone_PHONE_ID.

Let us see this in tabular form, as shown next:.

The table EMPLOYEE:

EMP_ID

EMP_TYPE

FIRST_NAME

LAST_NAME

32368

Perm

Vernon

Reid

40201

Contractor

Paul

Gilbert

The table PHONE

PHONE_ID

TYPE

INTER_CODE

AREA_CODE

LOCAL_CODE

1002

Work

+44

207

5459923

1004

Work Fax

+44

207

5451234

1006

Home

+1

812

1237884

The table EMPLOYEE_PHONE

Employee_EMP_ID

Phone_PHONE_ID

32668

1002

32368

1004

40201

1008

Of course, we assume that the underlying database allows lower and upper case names for its entities.

One-to-many relationship with a join column

A @OneToMany can be defined with either a join table, or foreign key in the target object's table referencing the source object table's primary key. If we choose the second option, with the foreign key in the target entity then to uphold the relationship, we need to add a @JoinColumn annotation to the list collection field or property accessor.

Let's add a join column to the employee entity:

@Entity
public class Employee implements java.io.Serializable {
  /*...*/
  
  @OneToMany(cascade = CascadeType.ALL)
  @JoinColumn(name="EMP_FK_ID",
    referencedColumnName="EMP_ID")
  private List<Phone> phones;    
}

Here the join column is actually created as part of the dependent entity Phone. In other words, the extra column is a foreign key in the target entity, which the entity directly has no responsibility to take care of and there is no equivalent in Java!

Consequently, a unidirectional one-to-many mapping is only officially supported in JPA 2.0 or better. Such a standard conforming persistence provider creates a database table PHONE with an additional foreign key column EMPLOYEE_FK_ID. The join table is unnecessary in this relationship type.

The table PHONE looks like the following:

PHONE_ID

TYPE

INTER_CODE

AREA_CODE

LOCAL_CODE

EMP_FK_ID

1002

Work

+44

207

5459923

32368

1004

Work Fax

+44

207

5451234

32368

1006

Home

+1

812

1237884

40201

The solution to the update problem for an unknown foreign key, which has existed since JPA 1.0, is to make the one-to-many relationship bidirectional, or use an explicit join table with an explicit foreign constraint that always enforces a one-to-many relationship in the database.

Let's look at the bidirectional form first.

Bidirectional one-to-many relationship

The target entity requires a many-to-one mapping.

The Phone entity takes a new property, the employee, and references to the owning entity.

@Entity
public class Phone implements java.io.Serializable {
    /* ... as before ... */
    @ManyToOne
    @JoinColumn(name="EMP_ID_FK")
    private Employee employee;
}

Now the Phone entity knows about the database column as a foreign key. We can certainly access the employee in Java programming.

In order to be bidirectional the owning entity must be configured with an inverse mapping. It needs to know what the field is or the property accessor that provides the inverse reference back to the source entity.

For the Employee entity, we provide this information with the mappedBy attribute.

@Entity
public class Employee implements java.io.Serializable {
    /*... */
    
    @OneToMany(cascade=CascadeType.ALL, mappedBy="employee")
    private List<Phone> phones;
    
    /*...*/
}

The @OneToMany signifies that the list collection of Phone entities is managed and owned by the Employee and there is an inverse relationship through the method call chain Employee.getPhones().get(N).getEmployee(), where N is some primitive integer type.

Therefore to add a new Phone and to remove a Phone entity record, we can have methods in the Employee entity like the following:

@Entity
public class Employee implements java.io.Serializable {
  /*...*/
  public boolean addPhone( Phone phone) {
    if ( ! phones.contains( phone) ) {
      Employee oldEmployee = old.getEmployee();
      if ( oldEmployee != null ) {
      removePhone( oldEmployee )
    }
  phones.add( phone );
    return true;
    }
  else { return false; }
  }

  public boolean removePhone( Phone phone ) {
    if ( phones.contains( phone) ) {
      phones.remove(phone);
      phone.setEmployee(null);
      return true;
    }
  else { return false; }
  }
}

It is very important to ensure that in the Java application both references link to each other.

The removePhone() safely demonstrates how to delete the Phone entity from the employee entity and sets the reference to null; there is a check that the record is part of the collection beforehand.

The addPhone() adds a new phone entity to the employee's list collection provided it is not already contained. We sanity check the method by removing the Phone entity from the old Employee record, if any, and check if it was managed beforehand by reusing the removePhone() method. The new phone entity is added to the employee's current list collection, and the inverse relationship is also set in the phone entity.

One-to-many using an explicit join table

JPA allows developers to explicitly define a join table with the candidate keys from the respective database tables. The @javax.persistence.JoinTable annotation configures join table for all of the types of relationship: @OneToOne, @OneToMany, @ManyToOne, and @ManyToMany. The @JoinTable annotation specifies the owning side of the relationship in Java. It requires an array of join columns and for inverse relationship an array of inverse join columns.

In the following code,, we have our two entities Employee and Phone. The Employee entity-side is annotated explicitly as a join table:

@Entity
public class Employee implements java.io.Serializable {
  /*...*/
    
  @OneToMany(cascade = CascadeType.ALL)
  @JoinTable(name="EMP_PHONE_LINK",
    joinColumns=
      @JoinColumn( name="EMP_FK",
        referencedColumnName="EMP_ID"),
      inverseJoinColumns=
            @JoinColumn( name="PHONE_FK",
                referencedColumnName="PHONE_ID",
                unique=true )
    )
    private List<Phone> phones;    
}

The phone list collection field is annotated with @JoinTable, with a single join column and a single inverse join column. Of course, we could have additional columns in a combination of primary and foreign keys for advanced situations.

With the code above, the JPA provider creates a database join table called EMP_PHONE_LINK with two foreign columns, namely EMP_FK and PHONE_FK. Excuse the badly named database column, but I think it illustrates the point—the reference column names points back to the constituent entities and therefore database tables: EMP_ID and PHONE_ID.

In order to enforce the constraint of the one-to-many relationship, we set the unique attribute, which is on the @JoinColumn, to true on the inverse part of the relationship.

If you choose not to specify a table explicitly, then the default join table name of the join table is a concatenation of the owning entity and the dependent names, delimited with an underscore.

This concludes the section on one-to-many relationship in JPA. We will now move on to the inverse mapping.

Many-to-one mapping

The many-to-one mapping relationship associates a collection of multiple entities directly to one single entity. The annotation is @javax.persistence.ManyToOne. The source entities collectively share ownership of a single entity.

The inverse relationship of a many-to-one is a one-to-many. In comparison to a many-to-many relationship, remember that inverse of a many-to-many relationship is itself.

Let us look at the full attributes of the @ManyToOne annotation:

Attribute

Type

Description

Default Value

targetEntity

String

This optional attribute represents the entity class that is the target of the relationship. If the property is used as a raw type then the attribute must be specified.

The parameterized type of the collection when defined using Java generics

cascade

String

This attribute specifies how and when the lifecycle of the dependent entity is included in any cascade operations (CascadeType.ALL, CascadeType.PERSIST etc.)

No operations are cascaded

fetch

String

This attribute specifies how the dependent entity is retrieved in a relationship. The valid values are FetchType.EAGER and FetchType.LAZY.

FetchType.EAGER

optional

Boolean

This attribute specifies if the relationship can be null or not. The default value is true; and by setting this to false then a non-null relationship must exist between the entities.

true

Many-to-one relationship with a join column

Let us take two different entities for this example: many projects have an association to a particular project type, or expressed in the reverse: for a given type there can be zero or more projects.

Here is the ProjectType entity:

@Entity
public class ProjectType implements java.io.Serializable {
    @Id private int id;
    private String name;
    private String description;
    /* ... */
}

Here is the Project entity, which is the owner of the relationship:

@Entity
public class Project implements java.io.Serializable {
    @Id private int id;
    private String name;
    private String description;

    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="PROJ_TYPE_FK")
    private ProjectType type;
    
    public ProjectType getType() { return type; }
    public void setType(ProjectType type) {
        this.type = type; }
    /* ... */
}

In the above class Project, the @JoinColumn annotation configures the additional database column with a name PROJ_TYPE_FK. By default, the persistence provider will concatenate the entity name with the foreign key name delimited with an underscore character (the database table column PROJECT_TYPE_ID).

Most applications will use @ManyToOne with the @JoinColumn in order to configure an alternative database column name.

The relationship between the Project and ProjectType is unidirectional in the example and here are the possible states of the database tables:

PROJECT_TYPE (table):

ID

Name

Description

579

FXTRADING

FX Trading

404

MARKETING

Trading Sales and Marketing

PROJECT (table):

ID

Name

Description

PROJ_TYPE_FK

1

FXDAILYREP

FX daily trading report

579

2

ONBOARD

New customer onboarding project

404

3

FXFIXINCOME

FX Fix Income Upgrade

579

Bidirectional many-to-one relationship

The bidirectional many-to-one relationship is the exact mirror on the one-to-many relationship. The only difference is that the entity is ultimately the owner of the relationship in terms of a Java programming. See the section One-to-many mapping.

Be careful with cascade operations in a many-to-one mapping, especially in circumstances where the single entity is used like a database enumeration type. Removing an entire collection of project records could delete the project type too. You probably want to manage the cascade types with a set of defined operations.

Many-to-many mapping

The many-to-many mapping relationship associates a collection of multiple entities to another collection of multiple entities. In the Java Persistence, this annotation is called @javax.persistence.ManyToMany. The Java developer must define which side of the relationship is the owner regardless of whether the true association is unidirectional or bidirectional. In database terms, all many-to-many associations are by definition bidirectional.

The inverse relationship of a many-to-many is a many-to-many, which is different to the associations of one-to-many and many-to-one.

All @ManyToMany associations require a @JoinTable as this is the practical way to represent this relationship in a relational database.

Let us look at the full attributes of the @ManyToMany annotation:

Attribute

Type

Description

Default value

targetEntity

String

This optional attribute represents the entity class that is the target of the relationship. If the property is used as a raw type then the attribute must be specified.

The parameterized type of the collection when defined using Java generics

cascade

String

This attribute specifies how and when the lifecycle of the dependent entity is included in any cascade operations (CascadeType.ALL, CascadeType.PERSIST etc.)

No operations are cascaded

fetch

String

This attribute specifies how the dependent entity is retrieved in a relationship. The valid values are FetchType.EAGER and FetchType.LAZY.

FetchType.LAZY

mappedBy

String

This attribute specifies the field or accessible property accessor for the source owning entity for bidirectional relationships.

None

Bidirectional many-to-many relationship

In the example code, we extend the Project entities with a many-to-many association of Employee entities. That is, multiple projects have zero or one employee and zero or one project have multiple employees.

Here is the revised class for Project:

@Entity
public class Project implements java.io.Serializable {
    @Id private int id;
    /*...*/

    @ManyToMany(cascade={CascadeType.PERSIST,
        CascadeType.MERGE,CascadeType.DETACH)}
    @JoinTable(name="PROJECT_EMPLOYEE",
        joinColumns={ @JoinColumn(name="PROJ_ID_FK",
            referencedColumnName="ID" ) }, 
        inverseJoinColumns={
            @JoinColumn(name="EMPL_ID_FK",
            referencedColumnName="EMP_ID" ) }
    private List<Employee> employees;
    
    public List<Employee> getEmployees() { return employees; }
    public void setEmployees(List<Employee> employees) {
        this.employees = employees; }
    
    /* ... */
}

Because this class Project declared the list of employees with a join table, it is the owner of the relationship. The database table is explicitly defined as PROJECT_EMPLOYEE; the join columns are appropriately named as PROJ_ID_FK and EMP_ID_FK, which are foreign keys to their respective tables.

Project configures a limited set of cascade operations from the Project to the Employee. By default, the case operations do not take place, but we allow general persistence, merging, and detaching of entities.

Let us tie the other side of the relationship into the Employee entity.

@Entity
public class Employee implements java.io.Serializable {
    /*...*/
    
    @ManyToMany(mappedBy="employees")
    private List<Project> projects;    

    public List<Project> getProjects() { return projects; }
    public void setProjects(List<Project> projects) {
        this.projects = projects; }
}

An employee has a set of projects or not, and we complete the definition of bidirectional relationship by declaring projects are owned by the Employee entity. We do this with the mappedBy attribute. It is important to define the mappedBy attribute in order to prevent duplicate join table being added to the database.

The JPA provider assumes that there are actually two separate relationships: a one-to-many and many-to-one, when the mappedBy attribute is not used. This could actually be the requirement for your business application, but it might be better to annotate the entities as properly separate @OneToMany and @ManyToOne with defined @JoinTable to avoid confusion.

Here are the sample database tables for the previous code:

PROJECT (table)

ID

Name

Description

1

FXDAILYREP

FX daily trading report

2

ONBOARD

New customer onboarding project

3

FXFIXINCOME

FX Fix Income Upgrade

EMPLOYEE (table)

EMP_ID

FIRST_NAME

LAST_NAME

32368

Vernon

Reid

40201

Paul

Gilbert

50203

Jennifer

Batten

60205

Joe

Satriani

PROJECT_EMPLOYEE

EMP_ID_FK

PROJ_ID_FK

32368

3

40201

2

50203

1

50203

3

40201

2

60205

3

Unidirectional many-to-many relationship

Mapping a unidirectional many-to-many relationship is fairly straightforward. The association has to be declared on the owner side with a @ManyToMany. The target association has no direct relationship to the owner: no @ManyToMany is required.

Let's take another example with the project entity. Every project has zero or more milestones, and some milestones are shared between projects.

Here is the Project code with a new field, a list collection of Milestone entities:

@Entity
public class Project implements java.io.Serializable {
    @Id private int id;
    /*...*/

    @ManyToMany(cascade=CascadeType.ALL, fetch=LAZY )
    @JoinTable(name="PROJECT_HAS_MILESTONE",
        joinColumns={ @JoinColumn(name="PROJ_ID_FK",
            referencedColumnName="ID" ) }, 
        inverseJoinColumns={
            @JoinColumn(name="MILESTONE_ID_FK",
            referencedColumnName="ID" ) }
    private List<Milestone> milestones;
    
    public List<Milestone> getMilestones() { return milestones; }
    public void setMilestones(List<Milestones> milestones) {
        this.milestones = milestones; }
    
    /* ... */
}

We use a join table as always for many-to-many association. The @JoinTable annotation declares the table name as PROJECT_HAS_MILESTONE, and the join columns at PROJ_ID_FK and MILESTONE_ID_FK respectively. So this code is semantically the same as the previous bidirectional example between projects and types.

Here is the code for the Milestone entity bean:

@Entity
public class Milestone implements java.io.Serializable {
    @Id private int id;
    @Column(nullable=false)
    private String name;
    private float tolerance;
    @Column(nullable=false)
    private String requirements;
    @Temporal(TIMESTAMP) private Date startDate;
    @Temporal(TIMESTAMP) private Date finishDate;
    /* ... */
}

In a unidirectional @ManyToMany association we do not declare the target side of the relationship and therefore there is no need for the annotation in the Milestone object.

As with all bidirectional relationships, Java Persistence requires the developer to connect object instances with each other. There is no secret sauce in the current JPA 2.1 specification that automates these connections.

Finally, we switch the cascade operation on the owner side of the many-to-many relationship back to CascadeType.ALL. So persistence will perform operations such as CascadeType.PERSIST and CascadeType.REMOVE on the dependent Milestone records, if the master Project entity is affected. As with all performance questions, always take measurements before and after, multiple times within a micro-benchmark—don't guess! Use the measurements to reason about the bottlenecks before modifying application code.

This concludes the entire section on entity relationship mapping.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.189.23