Pages

Table per concrete class with implicit polymorphism

Table per concrete class with implicit polymorphism

For this type, every class (excluding abstract class and interface type) can use one table. All properties of a class including super class properties can be mapped to columns of a table. Hibernate still knows about the superclass because it scans the persistent classes on startup.

Note: (1) The main problem with this approach is, it doesn't support polymorphic association very well,  All subclasses are mapped to different tables and polymorphic association to their superclass can not be represented as a simple foreign key.

(2)  Query against super class executes several SELECT statements (for every concrete class)  for polymorhic queries.

(3) A change to superclass properties effects the several columns of different tables in the database. It also makes it much more difficult to implement database integrity constraints that apply to all subclasses

Let's see this example, suppose one user apply for credit card in a bank so user have three entity classes as follow : CreditCardHolder , CreditCardDetails, BankAccountDetails


public abstract class CreditCardHolder {

private String owner;
// generates the setter and getter method 
}

public class CreditCardDetails extends CreditCardHolder {

private Long creditCardId;
private String number;
private String expMonth;
private String expYear;
      // generates the setter and getter method 
}

public class BankAccountDetails extends CreditCardHolder {

private Long bankAccountId;
private String account;
private String bankName;


       // generates the setter and getter method 
}
and two mapping files CreditCardDetails.hbm and BankAccountDetails.hbm.xml


<hibernate-mapping package="table.per.concrete_class.with.implicit.polymorphism">
<class name="CreditCardDetails" table="CREDIT_CARD_DETAILS">
<id name="creditCardId" column="CREDIT_CARD_ID">
<generator class="increment"/>
</id>

<!-- This is inherited property from the super class -->
<property name="owner" column="OWNER"/> 

<property name="number" column="CREDIT_CARD_NUMBER"/>
<property name="expMonth" column="EXP_MONTH"/>
<property name="expYear" column="EXP_YEAR"/>
</class>
</hibernate-mapping>

<hibernate-mapping package="table.per.concrete_class.with.implicit.polymorphism">
<class name="BankAccountDetails" table="BANK_ACCOUNT_DETAILS">
<id name="bankAccountId" column="BANK_ACCOUNT_ID">
<generator class="increment"/>
</id>

<!-- This is inherited property from the super class -->
<property name="owner" column="OWNER"/>

<property name="account" column="ACCOUNT_TYPE"/>
<property name="bankName" column="BANK_NAME"/>
</class>
</hibernate-mapping>

Now if you try to run this following code, it will save all details into the database.

public class HibernateTest {

private final static Logger LOGGER = Logger.getLogger(HibernateTest.class); 

/**
* @param args
*/
public static void main(String[] args) {
LOGGER.info("starting of main method");
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction txn = session.beginTransaction();

CreditCardDetails creditCard = new CreditCardDetails();
creditCard.setNumber("3423243234342");
creditCard.setOwner("Sachin Verma");
creditCard.setExpMonth("10/18");
creditCard.setExpYear("2018");
session.saveOrUpdate(creditCard);

txn.commit();
session.close();
HibernateUtil.shutDown();
}
}
See the hibenrate generated comment on console

Oct 15, 2012 2:33:47 PM org.hibernate.connection.C3P0ConnectionProvider configure
WARNING: No JDBC Driver class was specified by property hibernate.connection.driver_class
14:33:48,050 INFO AbstractPoolBackedDataSource:462 - Initializing c3p0 pool... com.mchange.v2.c3p0.PoolBackedDataSource@7d7cbdca [ connectionPoolDataSource -> com.mchange.v2.c3p0.WrapperConnectionPoolDataSource@c967e745 [ acquireIncrement -> 1, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, debugUnreturnedConnectionStackTraces -> false, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1bs1yqt8qrnitp2sbu28m|187b217, idleConnectionTestPeriod -> 3000, initialPoolSize -> 5, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 300, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 20, maxStatements -> 100, maxStatementsPerConnection -> 0, minPoolSize -> 5, nestedDataSource -> com.mchange.v2.c3p0.DriverManagerDataSource@c2a4e33e [ description -> null, driverClass -> null, factoryClassLocation -> null, identityToken -> 1bs1yqt8qrnitp2sbu28m|28ef8f, jdbcUrl -> jdbc:mysql://localhost:3306/HibernateTest, properties -> {autocommit=true, user=******, password=******} ], preferredTestQuery -> null, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false; userOverrides: {} ], dataSourceName -> null, factoryClassLocation -> null, identityToken -> 1bs1yqt8qrnitp2sbu28m|1cefd3c, numHelperThreads -> 3 ]
Oct 15, 2012 2:33:48 PM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: schema export complete
Oct 15, 2012 2:33:48 PM org.hibernate.impl.SessionFactoryImpl checkNamedQueries
INFO: Checking 0 named queries
Hibernate: insert into CREDIT_CARD_DETAILS (OWNER, CREDIT_CARD_NUMBER, EXP_MONTH, EXP_YEAR, CREDIT_CARD_ID) values (?, ?, ?, ?, ?)
Oct 15, 2012 2:33:48 PM org.hibernate.impl.SessionFactoryImpl close
INFO: closing






2 comments: