JAKARTA EE FOR JUNIOR DEVELOPERS - Lesson 4 Entity Class (Part 2)

 


INTRODUCTION
In this lesson of Jakarta EE for Junior Developers, we will see how we can create a table in the database with a different name from that of the entity, as well as column names different from the names of the variables. We will also explain what access type means and the purpose of the @Transient annotation.
NAMING OF DATABASE TABLES

So far, we have managed to create an entity class and map it to a database table. As you may have already noticed, the name of the table is the same as the name of the entity, as this is the default behavior of Jakarta EE Persistence.

Most of the time, we prefer to name the tables using plural forms, such as Employees, Departments, etc. At the same time, we don't want to change the names of our entities, as this is more convenient for developing our code. Is there a way we can create tables in the database with names different from the entity names?

Section 2.14 of Jakarta EE Persistence specification refers to an annotation called @Table. This annotation includes an element that allows you to assign a new name to the entity.

When we add the @Table annotation to the top of our class, we'll also need to import the corresponding Jakarta library.

Open a parentheses right after @Table and assign a value to the name attribute, which will be the new name of the table.



Go to the services and delete any tables you may have created in previous lessons from the database. Next, right-click on the project and execute the 'Clean and Build' command. Once that’s done, execute the 'Run' command. When the project loads, a new table named 'Employees' should be created in the database.


CREATING MORE COLUMNS

Our Employees table currently contains only one column, the primary key 'Id' column. A more practical employees table should include additional information about each employee. To achieve this, we need to add more columns. So, let's add the following instance variables to the entity class:


NetBeans provides a quick way to create getter and setter methods for these private fields. All we need to do is right-click anywhere inside the Employee entity class, and from the menu that appears, select 'Insert Code.


From the next menu, select Getter and Setter.


Finally, select all the fields that appear in the window and click 'Generate.' Now, we have all the getter and setter methods created for the private instance variables we've added to our class.


If we clean our database by deleting any existing tables and then run the project again, our new table with the added columns should be created.


NAMING OF TABLE COLUMNS

There is an annotation called @Column that allows you to specify a preferred name for columns within the table. For example, if we want to save the variable firstName as First_Name, we can use this annotation. To achieve this, simply add the @Column annotation before each variable whose name you want to change.

In addition to the name attribute, we can specify other attributes for the column, such as whether null values are allowed. Finally, notice that for the salary variable, we use the @Column annotation to define the precision of the number. Precision refers to the total number of digits that can be stored.

Let's apply these new attributes to the variables now.

Employee.java

package com.mycompany.jakartaee.entities;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.io.Serializable;
import java.util.Date;

@Entity
@Table(name = "EMPLOYEES")
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column(name = "first_name", nullable = false)
    private String firstName;
    @Column(name = "last_name", nullable = false)
    private String lastName;
    private String email;
    private String phoneNumber;
    @Column(name = "hire_date", nullable = false)
    private Date hireDate;
    @Column(precision = 6)
    private Double salary;
 
    public Long getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public Date getHireDate() {
        return hireDate;
    }

    public void setHireDate(Date hireDate) {
        this.hireDate = hireDate;
    }

    public Double getSalary() {
        return salary;
    }

    public void setSalary(Double salary) {
        this.salary = salary;
    }

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

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Employee)) {
            return false;
        }
        Employee other = (Employee) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "com.mycompany.jakartaee.entities.Employee[ id=" + id + " ]";
    }
   
}


FIELD ACCESS vs. PROPERTY ACCESS

In Jakarta EE Persistence (Section 2.3), access type refers to how Persistence accesses the entity's fields (properties) to persist data into the database. It essentially defines whether Persistence will access the entity's fields directly or use getter/setter methods to perform operations like reading or writing data.

We're already familiar with how field access works, as that's what we've been using so far. Now, let's make a small modification to our entity class.

Let's move the @Id annotation from the instance variable to the getId() method. This will automatically activate property access mode, meaning the column names will now be derived from the getter methods, completely ignoring the names of the instance variables. Note that the instance variable salary has been renamed to monthlySalary, but the getter and setter methods remain unchanged. As a result, the column name will be derived from the getter method, not the variable.


Employee.java

package com.mycompany.jakartaee.entities;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.io.Serializable;
import java.util.Date;

@Entity
@Table(name = "EMPLOYEES")
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;
   
    private Long id;
    @Column(name = "first_name", nullable = false)
    private String firstName;
    @Column(name = "last_name", nullable = false)
    private String lastName;
    private String email;
    private String phoneNumber;
    @Column(name = "hire_date", nullable = false)
    private Date hireDate;
    @Column(precision = 6)
    private Double monthlySalary;
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public Date getHireDate() {
        return hireDate;
    }

    public void setHireDate(Date hireDate) {
        this.hireDate = hireDate;
    }

    public Double getSalary() {
        return monthlySalary;
    }

    public void setSalary(Double salary) {
        this.monthlySalary = salary;
    }

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

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Employee)) {
            return false;
        }
        Employee other = (Employee) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "com.mycompany.jakartaee.entities.Employee[ id=" + id + " ]";
    }
   
}


However, we still haven't fully explained the term 'access type' mentioned in the specification (Section 2.3.2). We can explicitly specify the access type using the @Access annotation if we want to mix both field and property access within the same entity.

In the following modification of our entity class, we explicitly define the default access mode by annotating it with AccessType.FIELD. However, for the monthlySalary property, we override this access type and assign AccessType.PROPERTY to it.



Employee.java

package com.mycompany.jakartaee.entities;

import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.io.Serializable;
import java.util.Date;

@Entity
@Access(AccessType.FIELD)
@Table(name = "EMPLOYEES")
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column(name = "first_name", nullable = false)
    private String firstName;
    @Column(name = "last_name", nullable = false)
    private String lastName;
    private String email;
    private String phoneNumber;
    @Column(name = "hire_date", nullable = false)
    private Date hireDate;
    @Column(precision = 6)
    private Double monthlySalary;
 
   
    public Long getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public Date getHireDate() {
        return hireDate;
    }

    public void setHireDate(Date hireDate) {
        this.hireDate = hireDate;
    }

    @Access(AccessType.PROPERTY)
    public Double getSalary() {
        return monthlySalary;
    }

    public void setSalary(Double salary) {
        this.monthlySalary = salary;
    }

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

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Employee)) {
            return false;
        }
        Employee other = (Employee) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "com.mycompany.jakartaee.entities.Employee[ id=" + id + " ]";
    }
   
}


It seems that our configuration worked, but now we have both fields related to salary created, because Jakarta EE Persistence executed both the field and property access modes for the same variable. To solve this issue, we need to use another annotation called @Transient (Section 11.1.54). When defining a custom access type for a field or property, the @Transient annotation tells Jakarta Persistence not to map it to the corresponding column in the database.


Let's build and run the application one more time. This time everything should work just fine.

package com.mycompany.jakartaee.entities;

import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
import java.io.Serializable;
import java.util.Date;

@Entity
@Access(AccessType.FIELD)
@Table(name = "EMPLOYEES")
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column(name = "first_name", nullable = false)
    private String firstName;
    @Column(name = "last_name", nullable = false)
    private String lastName;
    private String email;
    private String phoneNumber;
    @Column(name = "hire_date", nullable = false)
    private Date hireDate;
    @Column(precision = 6)
    @Transient
    private Double monthlySalary;
 
   
    public Long getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public Date getHireDate() {
        return hireDate;
    }

    public void setHireDate(Date hireDate) {
        this.hireDate = hireDate;
    }

    @Access(AccessType.PROPERTY)
    public Double getSalary() {
        return monthlySalary;
    }

    public void setSalary(Double salary) {
        this.monthlySalary = salary;
    }

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

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Employee)) {
            return false;
        }
        Employee other = (Employee) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "com.mycompany.jakartaee.entities.Employee[ id=" + id + " ]";
    }
   
}





full-width

Post a Comment

0 Comments