One-to-one relationships

One-to-one relationships occur when an instance of an entity can have zero or one corresponding instance of another entity.

One-to-one entity relationships can be bidirectional (each entity is aware of the relationship) or unidirectional (only one of the entities is aware of the relationship). In the CUSTOMERDB database, the one-to-one mapping between the LOGIN_INFO and the CUSTOMERS tables is unidirectional, since the LOGIN_INFO table has a foreign key to the CUSTOMERS table, but not the other way around. As we will soon see, this fact does not stop us from creating a bidirectional one-to-one relationship between the Customer entity and the LoginInfo entity.

The source code for the LoginInfo entity, which maps to the LOGIN_INFO table, can be seen here:

package net.ensode.javaee8book.entityrelationship.entity; 
 
import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.Id; 
import javax.persistence.JoinColumn; 
import javax.persistence.Table; 
 
@Entity 
@Table(name = "LOGIN_INFO") 
public class LoginInfo 
{ 
  @Id 
  @Column(name = "LOGIN_INFO_ID") 
  private Long loginInfoId; 
 
  @Column(name = "LOGIN_NAME") 
  private String loginName; 
 
  private String password; 
 
  @OneToOne  
@JoinColumn(name="CUSTOMER_ID")

private Customer customer;
public Long getLoginInfoId() { return loginInfoId; } public void setLoginInfoId(Long loginInfoId) { this.loginInfoId = loginInfoId; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getLoginName() { return loginName; } public void setLoginName(String userName) { this.loginName = userName; } public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } }

The code for this entity is very similar to the code for the Customer entity. It defines fields that map to database columns. Each field whose name does not match the database column name is decorated with the @Column annotation; in addition to that, the primary key is decorated with the @Id annotation.

Where the preceding code gets interesting is the declaration of the customer field. As can be seen in the code, the customer field is decorated with the @OneToOne annotation; this lets the application server know that there is a one-to-one relationship between this entity and the Customer entity. The customer field is also decorated with the @JoinColumn annotation. This annotation lets the container know which column in the LOGIN_INFO table is the foreign key corresponding to the primary key on the CUSTOMER table. Since LOGIN_INFO, the table that the LoginInfo entity maps to, has a foreign key to the CUSTOMER table, the LoginInfo entity owns the relationship. If the relationship were unidirectional, we wouldn't have to make any changes to the Customer entity. However, since we would like to have a bidirectional relationship between these two entities, we need to add a LoginInfo field to the Customer entity, along with the corresponding getter and setter methods.

Like we mentioned before, in order to make the one-to-one relationship between the Customer and LoginInfo entities bidirectional, we need to make a few simple changes to the Customer entity:

package net.ensode.javaee8book.entityrelationship.entity; 
 
import java.io.Serializable; 
import java.util.Set; 
 
import javax.persistence.CascadeType; 
import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.Id; 
import javax.persistence.OneToMany; 
import javax.persistence.OneToOne; 
import javax.persistence.Table; 
 
@Entity 
@Table(name = "CUSTOMERS") 
public class Customer implements Serializable 
{ 
  @Id 
  @Column(name = "CUSTOMER_ID") 
  private Long customerId; 
 
  @Column(name = "FIRST_NAME") 
  private String firstName; 
 
  @Column(name = "LAST_NAME") 
  private String lastName; 
 
  private String email; 
 
  @OneToOne(mappedBy = "customer") 
private LoginInfo loginInfo;

public LoginInfo getLoginInfo()

{

return loginInfo;

}

public void setLoginInfo(LoginInfo loginInfo)

{

this.loginInfo = loginInfo;

}
//Additional setters and getters omitted for brevity }

The only change we need to make to the Customer entity to make the one-to-one relationship bidirectional is to add a LoginInfo field to it, along with the corresponding setter and getter methods. The loginInfo field is decorated with the @OneToOne annotation. Since the Customer entity does not own the relationship (the table it maps to does not have a foreign key to the corresponding table), the mappedBy element of the @OneToOne annotation needs to be added. This element specifies which field in the corresponding entity has the other end of the relationship. In this particular case, the customer field in the LoginInfo entity corresponds to the other end of this one-to-one relationship.

The following Java class illustrates the use of the preceding entity:

package net.ensode.javaee8book.entityrelationship.namedbean; 
 
import javax.annotation.Resource; 
import javax.enterprise.context.RequestScoped; 
import javax.inject.Named; 
import javax.persistence.EntityManager; 
import javax.persistence.PersistenceContext; 
import javax.transaction.HeuristicMixedException; 
import javax.transaction.HeuristicRollbackException; 
import javax.transaction.NotSupportedException; 
import javax.transaction.RollbackException; 
import javax.transaction.SystemException; 
import javax.transaction.UserTransaction; 
import net.ensode.javaee8book.entityrelationship.entity.Customer; 
import net.ensode.javaee8book.entityrelationship.entity.LoginInfo; 
 
@Named 
@RequestScoped 
public class OneToOneRelationshipDemoBean { 
 
    @PersistenceContext 
    private EntityManager entityManager; 
 
    @Resource 
    private UserTransaction userTransaction; 
 
    public String updateDatabase() { 
        String retVal = "confirmation"; 
        Customer customer; 
        LoginInfo loginInfo = new LoginInfo(); 
 
        loginInfo.setLoginInfoId(1L); 
        loginInfo.setLoginName("charlesj"); 
        loginInfo.setPassword("iwonttellyou"); 
 
        try { 
            userTransaction.begin(); 
 
            customer = entityManager.find(Customer.class, 4L); 
            loginInfo.setCustomer(customer); 
 
            entityManager.persist(loginInfo); 
 
            userTransaction.commit(); 
 
        } catch (NotSupportedException | 
                SystemException | 
                SecurityException | 
                IllegalStateException | 
                RollbackException | 
                HeuristicMixedException | 
                HeuristicRollbackException e) { 
            retVal = "error"; 
            e.printStackTrace(); 
        } 
 
        return retVal; 
    } 
} 

In this example, we first create an instance of the LoginInfo entity and populate it with some data. We then obtain an instance of the Customer entity from the database by invoking the find() method of EntityManager (data for this entity was inserted into the CUSTOMERS table in one of the previous examples). We then invoke the setCustomer() method on the LoginInfo entity, passing the customer object as a parameter. Finally, we invoke the EntityManager.persist() method to save the data in the database.

What happens behind the scenes is that the CUSTOMER_ID column of the LOGIN_INFO table gets populated with the primary key of the corresponding row in the CUSTOMERS table. This can be easily verified by querying the CUSTOMERDB database.

Notice how the call to EntityManager.find() to obtain the customer entity is inside the same transaction from where we call EntityManager.persist(). This must be the case; otherwise, the database will not be updated successfully.
..................Content has been hidden....................

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