Entity Inheritance Using Abstract Entity

In my previous blog I shared my code re-factoring experience by using Mapped Superclass. Using Abstract Entity was another interesting experience. In our project there are some Entities like Customer, Vendor which have some common attributes like 'First Name', 'Last Name', etc. These attributes were defined  in both Customer and Vendor Class. This approach not only produced code duplication but also column duplication in underlying Datastore. JPA Abstract Entity feature inspires me to use a third Entity Class which is abstract to avoid this duplication.

Let's see how it works. Suppose you have two Entities Student and Teacher, and they have following attributes



Three attributes are common in this case and you can introduce a Person class which is abstract and has these common properties. Student and Teacher class will extend Person and only have their individual properties.

Your  Person, Student and Teacher Entity classes will be like this

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@Table(name = "persons")
public abstract class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id_nr")
    protected Long idNr;
    @Column(name = "first_name")
    protected String firstName;
    @Column(name = "last_name")
    protected String lastName;
    
    public Person() {
    } 
    //getter setter of the properties ....


@Entity
@Table(name = "teachers")
public class Teacher extends Person {
    private static final long serialVersionUID = 1L;
    @Column(name = "designation")
    protected String designation;
    // constructor, getter setter of the property....


@Entity
@Table(name = "students")
public class Student extends Person {
    private static final long serialVersionUID = 1L;
    @Column(name = "role_number")
    protected String roleNumber;
    // constructor, getter setter of the property.... 

For above scenario three tables will be generated in the database, persons, students and teachers. Mapping strategy of @Inheritance annotation has a great impact in table generation process. As we have used InheritanceType.JOINED as the mapping strategy, three different tables are created. If we were using default mapping strategy which is InheritanceType.SINGLE_TABLE, only persons table will be created with all the attributes. In both cases Persistence provider will also create a discriminator column in the person table called DTYPE, which will store the name of the inherited entity used to create the person.

Now run the following code and see how data is stored in the database in this design.

        @PersistenceContext(unitName = "TaskBoard-ejbPU")
        EntityManager em;

        Teacher teacher = new Teacher();
        teacher.setFirstName("Sarwar");
        teacher.setLastName("Hossain");
        teacher.setDesignation("Associate Proffessor");
        teacher.setIdNr(null);
        em.persist(teacher);
        
        Student student = new Student();
        student.setFirstName("Shams");
        student.setLastName("Zawoad");
        student.setRoleNumber("001525");
        student.setIdNr(null);
        em.persist(student);
        em.flush();



If you try with InheritanceType.SINGLE_TABLE mapping strategy you will get the following output by running the same code

Attractive feature of abstract entities is that they can be queried just like concrete queries, which were not possible in Mapped Superclass. If an abstract entity is the target of a query, the query operates on all the concrete subclasses of the abstract entity.

Entity Inheritance Using Mapped Superclass

When I engaged myself into code re-factoring of our VELACORE project, I found that almost all Entities have four common properties createdBy, creationDate, modifiedBy and modificationDate.  I wanted to reduce this code duplication and found that JPA is providing Mapped Superclass for this type of requirement where state and mapping information are common to multiple Entity classes. It contains persistent state and mapping information, but is not Entitity. That is, it is not decorated with the @Entity annotation and is not mapped as an entity by JPA.

Mapped Superclasses do not have any corresponding tables in the underlying Datastore (that was also my requirement). Entities that inherit from the mapped Superclass define the table mappings. Mapped superclasses are specified by decorating the class with the javax.persistence.MappedSuperclass annotation.

Here is an example of using Mapped Superclass for entity inheritance

@MappedSuperclass
public class BaseEntity
{
    @Column(name = "created_by")
    private String createdBy;
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "creation_date")
    private Calendar creationDate;
    
   //getter setter of the properties ....
}

@Entity
public class Customer extends BaseEntity 
{
    @Column(name = "first_name")
    private String firstName;

    ...
}

@Entity
public class Invoice extends BaseEntity {
    @Column(name = "invoice_no")
    private String invoiceNo;

    ...
}


In the above code snippet BaseEntity is the MappedSuperclass which contains the mapping information of the common properties. Customer and Invoice are two Entities extending the BaseEntity. In this scenario only CUSTOMER and INVOICE tables will be created in the database not the BASEENTITY. "created_by" and "creation_date" columns will be present in both CUSTOMER and INVOICE tables.


Limitations of using Mapped Superclass :
-Mapped Superclasses are not queryable, and can’t be used in EntityManager or Query operations.
-Mapped Superclasses can’t be targets of entity relationships.

Total Pageviews

Tags

Twitter Updates
    follow me on Twitter

    Followers