Monday, December 9, 2013

Hibernate Tutorial - Part V

For previous posts, refer:
Hibernate tutorial Part - I
Hibernate tutorial Part - II
Hibernate tutorial Part - III

Hibernate tutorial Part - IV

In this post, we are going to take a look at ' Table per subclass' approach for inheritance.


Table per subclass:

This strategy, represents inheritance relationships as relational foreign key associations.Every class/subclass that declares persistent properties, including abstract classes and even interfaces has its own table.

Unlike the table per concrete class strategy, the table here contains columns only for each non inherited property (each property declared by the subclass itself) along with a primary key that is also a foreign key of the super class table.

Lets take a look at the class definitions and annotations:

User Class:

@Entity
@Table(name = "USER") 
@Inheritance(strategy=InheritanceType.JOINED)  
public class User implements Serializable{
     @Id    
     @Column(name = "USER_ID")
     private String userId;
     
     @Column(name = "USERNAME")
     private String userName;
     
     @Column(name = "PASSWORD")
     private String password;
     
     //setters and getters
}

Customer Class:

@Entity
@Table(name="CUSTOMER") 
@PrimaryKeyJoinColumn(name="USER_ID") 

public class Customer extends User implements Serializable{
     
     @Column(name = "ADDRESS1")
     private String address1;
     @Column(name = "ADDRESS2")
     private String address2;
     @Column(name = "CITY")
     private String city;
     @Column(name = "STATE")
     private String state;
     @Column(name = "COUNTRY")
     private String country;
     
     //setters and getters
}

InternalUser Class:

@Entity
@Table(name = "INTERNAL_USER") 
@PrimaryKeyJoinColumn(name="USER_ID") 
public class InternalUser extends User implements Serializable{
     /*Admin/Non Admin*/
     @Column(name = "ACCESSTYPE")
     private String accessType;
     /*Contract/Permament*/
     @Column(name = "EMPLOYMENTTYPE")
     private String employmentType;
     
     //setters and getters
}

Note:
1. For every record for subclass, there will be a record in USER table as well. For eg, if we save Customer and InternalUser, then there will be one record each in INTERNAL_USER AND CUSTOMER and two records in USER.
2. Hibernate uses outer join to query subclass data


Disadvantage of this approach:

Involves a number of joins to join child tables. This could cause issues when there is a huge hierarchy with lot of subclasses.

                                                Continued...

Thursday, December 5, 2013

Hibernate Tutorial - Part IV

For previous posts refer:
Hibernate tutorial Part - I
Hibernate tutorial Part - II
Hibernate tutorial Part - III

In this post, we will take a look at 'Table per class hierarchy' strategy of inheritance.


Table Per Class hierarchy:

In this approach, an entire class hierarchy can be mapped to a single table. This table includes columns for all properties of all classes in the hierarchy. The concrete subclass represented
by a particular row is identified by the value of a type discriminator column.

Lets take a look at the classes and their annotations:

User Class:

@Entity
@Table(name = "USER") 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(     name="USER_TYPE",     discriminatorType=DiscriminatorType.STRING )
@DiscriminatorValue(value="U") 
public class User implements Serializable{
     @Id    
     @Column(name = "USER_ID")
     private String userId;
     
     @Column(name = "USERNAME")
     private String userName;
     
     @Column(name = "PASSWORD")
     private String password;
     
     //setters and getters
}

Customer Class:

@Entity
@Table(name="USER") 
@DiscriminatorValue(value="C")     
public class Customer extends User implements Serializable{
     
     @Column(name = "ADDRESS1")
     private String address1;
     @Column(name = "ADDRESS2")
     private String address2;
     @Column(name = "CITY")
     private String city;
     @Column(name = "STATE")
     private String state;
     @Column(name = "COUNTRY")
     private String country;
     
     //setters and getters
}

Internal User Class:

@Entity
@Table(name = "USER") 
@DiscriminatorValue(value="I")
public class InternalUser extends User implements Serializable{
     /*Admin/Non Admin*/
     @Column(name = "ACCESSTYPE")
     private String accessType;
     /*Contract/Permament*/
     @Column(name = "EMPLOYMENTTYPE")
     private String employmentType;
     
     //setters and getters
}

Note:
@DiscriminatorColumn - Is used to define the discriminator column for the SINGLE_TABLE and JOINED inheritance mapping strategies. The strategy and the discriminator column are only specified in the root of an entity class hierarchy or sub hierarchy in which a different inheritance strategy is applied.

@DiscriminatorValue- Is used to specify the value of the discriminator column for entities of the given type.

Table Structure:
Single Table User with the following columns. Note the USER_TYPE column is used to distinguish between different entities.

USER_ID
USERNAME
PASSWORD
ADDRESS1
ADDRESS2
CITY
STATE
COUNTRY
USER_TYPE
ACCESSTYPE

EMPLOYMENTTYPE


Disadvantages of this approach:

  1. Columns for properties declared by subclasses must be declared to be nullable.
  2. Schema is not normalized. We’ve created functional dependencies between nonkey columns, violating the third normal form.
The advantage of this approach compared to others is performance. Since we have to query only a single table, this approach provides very good performance.

                                                Continued...




Wednesday, December 4, 2013

Hibernate Tutorial - Part III

For previous parts refer:
Hibernate tutorial Part - I
Hibernate tutorial Part - II


Inheritance Mapping:

In this post, I'm going to write about Inheritance mapping in Hibernate.

Essentially, there are 3 different types of inheritance mapping which could be achieved:
  1. Table per concrete class 
  2. Table per class hierarchy
  3. Table per subclass

1. Table per concrete class

In this type of mapping, we will have a table mapped to every concrete class in the hierarchy. Lets say we have the following class hierarchy for representing different users of the system.

  • Abstract class, User
  • Concrete subclass, Customer
  • Concrete subclass, InternalUser
Lets take a look at the class definitions and the the annotations for each of these classes.

User Class:

@Entity
@Table(name = "USER") 
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 
public class User implements Serializable{
     @Id    
     @Column(name = "USER_ID")
     private String userId;
     
     @Column(name = "USERNAME")
     private String userName;
     
     @Column(name = "PASSWORD")
     private String password;
     
     //setters and getters
}

Customer Class:

@Entity
@Table(name="CUSTOMER") 
    @AttributeOverrides({     
        @AttributeOverride(name="userName", column=@Column(name="FIRSTNAME")),     
        @AttributeOverride(name="password", column=@Column(name="LASTNAME")) })
public class Customer extends User implements Serializable{    
     @Column(name = "ADDRESS1")
     private String address1;
     @Column(name = "ADDRESS2")
     private String address2;
     @Column(name = "CITY")
     private String city;
     @Column(name = "STATE")
     private String state;
     @Column(name = "COUNTRY")
     private String country;
     
     //setters and getters
}

Internal User Class:

@Entity
@Table(name = "INTERNAL_USER") 
public class InternalUser extends User implements Serializable{
     /*Admin/Non Admin*/
     @Column(name = "ACCESSTYPE")
     private String accessType;
     /*Contract/Permament*/
     @Column(name = "EMPLOYMENTTYPE")
     private String employmentType;
     
     //setters and getters
}

Note:@Inheritance defines the inheritance strategy to be used for an entity class hierarchy. It is specified on the entity class that is the root of the entity class hierarchy.

Table structure:
The table USER will have columns USER_ID,USERNAME,PASSWORD.
The table CUSTOMER will have all the columns as in USER plus additional columns.
The table INTERNAL_USER will have all the columns as in USER plus additional columns.

Notice that the primary key (USER_ID) is present in all the three tables and is shared across these tables.

Disadvantages of this approach:

  1. The columns in the super class are duplicated in all the child tables.
  2. Difficult to represent FK relationships. Lets say we have a class LoginDetails, which has association with User (either Customer or InternalUser). From a schema point of view, LOGIN_DETAILS table should have a FK to the CUSTOMER table or INTERNAL_USER table. We cannot represent this polymorphic representation effectively in SQL, as we will need two columns to represent this FK.
  3. Changes to the super class fields will cause changes to all the child class tables.
  4. The Sql to fetch child class will result in large number of selects.
  5. You cannot use AUTO/Identity column for the primary key.
                                                                                                 Continued...