à1. Inheritance Mapping Model:
àBy using this ORM-mapping model
we can resolve/solve the "Inheritance Impedance mismatch"
problem.
àInheritance is again 2-types
1.
Generalization
2.
Realization
1. Generalization:
Ex:
class Payment {
protected String paymentId;
protected String merchant;
protected String amount;
//setter and getters
}
àHere attributes of the Payment
class need not to be protected they may even private also bcz Hibernate can
inherit setters and getters. But to follow the convention we are taking
protected and protected attributes can be inherited.
class CardPayment extends
Payment {
private String cardNo;
private String cardType;
private String cvv;
private String expiry;
//setter and getters
}
à Here CardPayment needs the same
attribute of the Payment class hence we should not re-declare the all the
attributes so we need to use Inheritance.
class ChequePayment
extends Payment {
private String checkNo;
private String bank;
private Date issueDate;
//setter and getters
}
à We want to store the CardPayment
details then we need to store the both Base class attribute and CardPayment (derived
class attributes).
àIn order to store these
information we can design tables in different ways as follows
àWe can persist all the class
details in different tables that means every concrete class will have their own
table hence it called as table per concrete class.
àConcrete class can carry the data
but abstract or interfaces will not carry the data, bcz we can create obj only
for concrete classes.
àWe can persist the one table for
Base class and by joining the condition to that Base class table to different tables
of all sub classes or Derived class tables called as Table per sub class.
àWe can persist all the class or
the whole class hierarchy classes details in one table called as Table per
class hierarchy.
That means we can
store data in 3-ways while working with Inheritance mapping Model. That means
Hibernate supports the three basic inheritance mapping strategies
1.
Table per class hierarchy
2.
Table per concrete class
3.
Table per sub class
àThese 3 are generalized ways of
mapping. In addition, Hibernate supports a fourth, slightly different kind of
polymorphism.
4.
Implicit polymorphism
1. Table per class hierarchy:
PAYMENT_HISTORY
(TABLE)
PAYMENT_ID
|
MERCHANT
|
AMOUNT
|
CARD_NO
|
CARD_TYPE
|
CVV
|
EXPIRY
|
CHECH_NO
|
BANK
|
EXPIRY
|
1
|
BIGBAZR
|
1000
|
|||||||
2
|
CENTRAL
|
2000
|
112122
|
VISA
|
122
|
01-Jan
|
|||
3
|
LIFE STYLE
|
3000
|
CH1222
|
SBI
|
01-Feb
|
session.get(CardPayment.class,2);
When we get the data
from the session then hibernate thinks it is a class which contains all the
data details but all the details is not there in the CardPayment hence we
should not map this class as normal class in mapping file so we should not map with
<class> rather we need to map <subclass> bcz it is sub class of
Payment. Hence now hibernate reads the parent class details also from mapping
metadata while inserting or retrieving the data. Similarly same for the
CheckPayment also.
session.get(Payment.class,2);
It returns the
CardPayment bcz of polymorphic Query and id 2 is belongs to CardPayment but
hibernate will not identify the whether the data is Payment or CardPayment.
Hence in order to differentiate which class obj has been persisted and which
class obj is retrieving we need to provide one differentiate column to identify
for the hibernate that’s where we need to provide one differentiate column
called as discriminator-value column.
PAYMENT_HISTORY
(TABLE)
PAYMENT_ID
|
MERCHANT
|
AMOUNT
|
CARD_NO
|
CARD_TYPE
|
CVV
|
EXPIRY
|
CHECH_NO
|
BANK
|
EXPIRY
|
TYPE
|
1
|
BIGBAZR
|
1000
|
PAY
|
|||||||
2
|
CENTRAL
|
2000
|
112122
|
VISA
|
122
|
01-Jan
|
CARD
|
|||
3
|
LIFE
STYLE
|
3000
|
CH1222
|
SBI
|
01-Feb
|
CHK
|
So we need to provide
the discriminator column value in Base class hbm file and write the 3-hbm files
with <class> tag for base class which is normal class and Derived classes
as <subclass> which is incomplete mapping and it is extending the mapping
meta data info from the super class.
àConfiguration
Approach:
Payment.hbm.xml:
<hibernate-mapping
package=>
<class name=Payment discriminator-value=>
<id>
<generator class=>
</id>
<discriminator/>
</class>
</hibernate-mapping>
CardPayment.hbm.xml:
<hibernate-mapping>
<subclass discriminator-value=>
</subclass>
</hibernate-mapping>
CheckPayment.hbm.xml:
<hibernate-mapping>
<subclass>
</subclass>
</hibernate-mapping>
àAnnotation Driven
Approach:
@Inheritance(strategy =
InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name =
"PAYMENT_TYPE", discriminatorType= DiscriminatorType.STRING)
@DiscriminatorValue(value =
"PAYMENT")
@Table(name =
"PAYMENT_HISTORY")
Note:
àAnnotations also will inherit
from one Annotation to another annotation.
2. Table per concrete class:
PAYMENT
|
|||
PAYMENT_ID
|
|||
MERCHANT
|
|||
|
AMOUNT
|
||
|
|||
CARD_PAYMENT
|
CHEQUE_PAYMENT
|
||
PAYMENT_ID
|
PAYMENT_ID
|
||
MERCHANT
|
MERCHANT
|
||
AMOUNT
|
AMOUNT
|
||
CARD_NO
|
CHECK_NO
|
||
CARD_TYPE
|
BANK
|
||
CVV
|
ISS_DT
|
||
EXPIRY
|
PAYMENT:
PAYMENT_ID
|
MERCHANT
|
AMOUNT
|
1
|
BIGBAZR
|
1000
|
CARD_PAYMENT:
PAYMENT_ID
|
MERCHANT
|
AMOUNT
|
CARD_NO
|
CARD_TYPE
|
CVV
|
EXPIRY
|
2
|
CENTRAL
|
2000
|
112122
|
VISA
|
122
|
01-Jan
|
CHEQUE_PAYMENT:
PAYMENT_ID
|
MERCHANT
|
AMOUNT
|
CHECH_NO
|
BANK
|
ISS_DT
|
3
|
LIFE STYLE
|
3000
|
CH1222
|
SBI
|
13-11-2015
|
àIf any change happen in the Payment
class that means if any extra attribute added in the Payment class it impact
the all the sub classes of its corresponding tables.
PAYMENT
|
|||
PAYMENT_ID
|
|||
MERCHANT
|
|||
AMOUNT
|
|||
|
PAYMENT_CHARGE
|
||
|
|
||
CARD_PAYMENT
|
CHEQUE_PAYMENT
|
||
PAYMENT_ID
|
PAYMENT_ID
|
||
MERCHANT
|
MERCHANT
|
||
AMOUNT
|
AMOUNT
|
||
CARD_NO
|
CHECK_NO
|
||
CARD_TYPE
|
BANK
|
||
CVV
|
ISS_DT
|
||
EXPIRY
|
PAYMENT:
PAYMENT_ID
|
MERCHANT
|
AMOUNT
|
PAYMENT_CHARGE
|
1
|
BIGBAZR
|
1000
|
10
|
CARD_PAYMENT:
PAYMENT_ID
|
MERCHANT
|
AMOUNT
|
CARD_NO
|
CARD_TYPE
|
CVV
|
EXPIRY
|
PAYMENT_CHARGE
|
2
|
CENTRAL
|
2000
|
112122
|
VISA
|
122
|
01-Jan
|
10
|
CHEQUE_PAYMENT:
PAYMENT_ID
|
MERCHANT
|
AMOUNT
|
CHECH_NO
|
BANK
|
ISS_DT
|
PAYMENT_CHARGE
|
3
|
LIFE STYLE
|
3000
|
CH1222
|
SBI
|
13-11-2015
|
10
|
àsession.get(CardPayment.class,2);
Dieclty goes to the
CARD_PAYMENT table and fetches the data based on the id.
àUnion Polymorphic
Queries:
session.get(Payment.class,1);àUnion polymorphic query
session.get(Payment.class,2);àUnion polymorphic query
session.get(Payment.class,3);àUnion polymorphic query
àIn Table per class hierarchy
based on the id 1st it identifies the record is there or not and
then using the discriminator column it will identifies the corresponding class
and populates the data into the obj.
àIn Table per concrete class
hierarchy when we specify the id as 2 then it will goes to the DB and hibernate
tries to combine/union all the tables in a single query (instead of multiple
queries) and then tries to identifies in which table id it is existing and then
populates the data into the class obj, Hence we need to write
<union-subclass> as the tag in each and every derived child class. That
means in order to get the data union all the class tables.
Note:
In order to query the
data from Table per concrete class Inheritance strategy the id should be unique
across the heirachy of tables then only it will identifies corresponding class
obj based on the id and by using union of all the class tables.
àUse Case:
For example if we go
to the shopping-mall then we pay the payment using payment or card or cheque and
assume we pay via Card then we if we go again to the shopping-mall for exchange
then they scan the paymentId and based on the paymentId they scanned it needs to
fetch the details of CardPayment from their DB but they never enter the card
details so in this use case polymorphic queries are use full.
àPayment.hbm.xml:
<hibernate-mapping package="com.tpcc.entities">
<class name="Payment" table="PAYMENT">
<id name="paymentId"
type="int">
<column
name="PAYMENT_ID" />
<generator class="increment"
/>
</id>
<property
name="merchant" type="string">
<column
name="MERCHANT" />
</property>
<property
name="amount" type="float">
<column
name="AMOUNT" />
</property>
</class>
</hibernate-mapping>
àCardPayment.hbm.xml
<hibernate-mapping package="com.tpcc.entities">
<union-subclass name="CardPayment" extends="Payment"
table="CARD_PAYMENT">
</union-subclass>
</hibernate-mapping>
àChequePayment.hbm.xml
<hibernate-mapping package="com.tpcc.entities">
<union-subclass name="ChequePayment" extends="Payment"
table="CHEQUE_PAYMENT">
</union-subclass>
</hibernate-mapping>
àAnnotation Driven
Approach:
@Table(name = "PAYMENT")
@Inheritance(strategy =
InheritanceType.TABLE_PER_CLASS)
@AttributeOverrides({
@AttributeOverride(name = "paymentId", column =
@Column(name = "CRD_PAYMENT_ID")),
@AttributeOverride(name = "merchant", column = @Column(name
= "CRD_MERCHANT")),
@AttributeOverride(name = "AMOUNT", column = @Column(name =
"CRD_AMOUNT")) })
@Id
@GeneratedValue(generator =
"hib-generator")//jpa
//hibernate
@GenericGenerator(name =
"hib-generator", strategy = "increment") @Column(name =
"PAYMENT_ID")
3. Table per sub class:
àIn Table per class heirachy
column names are duplicated across all the sub class tables. So to avoid the
duplication of columns in all the sub class tables we are going for Table per
subclass.
PAYMENT:
PAYMENT_ID
|
MERCHANT
|
AMOUNT
|
||||||
1
|
BIGBAZR
|
1000
|
||||||
2
|
LIFE STYLE
|
2000
|
||||||
3
|
PANTALOONS
|
3000
|
||||||
CARD_PAYMENT:
|
||||||||
CARD_PAYMENT_ID
|
CARD_NO
|
CARD_TYPE
|
CVV
|
EXPIRY
|
||||
2
|
112122
|
VISA
|
122
|
01-Jan
|
||||
CHEQUE_PAYMENT:
|
||||||||
CHEQUE_PAYMENT_ID
|
CHECH_NO
|
BANK
|
ISS_DT
|
|||||
3
|
CH1222
|
SBI
|
13-11-15
|
|||||
àsession.get(CardPayment.class,2);
When we tries to fetch
the data hibernate will not get the CardPayment details unless until we have
join relation with CardPayment and Payment that’s why we need to provide the PK
of PAYMENT table as join column to CardPayment called as key-column which makes
the joining of 2-tables while getting the data.
àWhen we call
session.get(CardPayment.class,2); then hibernate will goes to the CardPayment
and makes join query with Payment as equi-join bcz we are directly specifying
the CardPayment and gets the data.
àIf session.get(Payment.class,2);
then hibernate will makes polymorphic query against all the classes and makes
the left-outer join with super class table and all the tables of sub classes
bcz we specified Payment.class which will tries to identifies the corresponding
class obj based on the join condition with all the tables and their key-column
(PK of Payment as FK in all sub classes) then gives the data. So it tries to
get the data by joining the super class table with sub class table hence we
need to specify the tag <join-subclass> in all the sub class mapping
files.
Left outer join means
always Payment details and either CardPayment or ChequePayment.
Payment.hbm.xml
<hibernate-mapping
package="com.tpsc.entities">
<class name="Payment"
table="PAYMENT">
<id name="paymentId"
type="int">
<column
name="PAYMENT_ID" />
<generator
class="increment" />
</id
</class>
</hibernate-mapping>
CardPayment.hbm.xml:
<hibernate-mapping
package="com.tpsc.entities">
<joined-subclass
name="CardPayment" extends="Payment"
table="CARD_PAYMENT">
<key column="CRD_PAYMENT_ID"
/>
</joined-subclass>
</hibernate-mapping>
ChequePayment.hbm.xml:
<hibernate-mapping
package="com.tpsc.entities">
<joined-subclass name="ChequePayment"
extends="Payment"
table="CHEQUE_PAYMENT">
<key column="CHQ_PAYMENT_ID"
/>
</joined-subclass>
</hibernate-mapping>
àAnnotation Driven
Approach:
@Entity
@Table(name =
"PAYMENT")
@Inheritance(strategy =
InheritanceType.JOINED)
@Entity
@Table(name =
"CARD_PAYMENT")
@PrimaryKeyJoinColumn(name =
"CRD_PAYMENT_ID")
4.
Implicit polymorphism:
àIt is specific to hibernate it
not a general ORM based mapping model.
àIn this approach individual
tables will be created for super class and it’s for each and every sub class.
àThere is no relation with one
mapping file with another mapping and while persisting hibernate will identifies
based on the inheritance relation between the classes.
Comments
Post a Comment