Pages

Converters in hibernate

Converters in hibernate

If you want to map a java.lang.Integer type property of a class with VARCHAR SQL type That time you have to write a custom mapping types using hibenrate. These are called converters.

Now, hibernate have provided some basic interface for converters which are as follows:

(1) org.hibernate.usertype.UserType
(2) org.hibernate.usertype.CompositeUserType
(3) org.hibernate.usertype.UserCollectionType
(4) org.hibernate.usertype.EnhancedUserType
(5) org.hibernate.usertype.UserVersionType
(6) org.hibernate.usertype.ParameterizedType








When to choose which strategy for inheritance mapping?

When to choose which strategy for inheritance mapping?

There are few rules for choosing inheritance strategy.
(1) If there is no need for polymorphic association and queries i.e if you use very rarely query for CreditCardHolder or you do not have any class that has association with CreditCardHolder class, That time you should use UNION based mapping ( Table per concrete class with union).

(2) If you requires a polymorphic association  or queries and subclasses has few properties That time , you should use table per class hierarchy (using subclass element in mapping metadata file).

(3) If you requires a polymorphic association  or queries and subclasses has many properties That time , you should use table per subclass (using join-subclass element in mapping metadata file) and if width and depth of inheritance hierarchy is high that time you should use Mixing inheritance strategy.


Mixing inheritance strategy

Mixing inheritance strategy

Till now, we have seen four type of inheritance strategy 
(1) Table per concrete class with implicit polymorphism
(2) Table per concrete class with union
(3) Table per class hierarchy
(4) Table per subclass 

Now, In this strategy, we can not mix above four type strategy to solve a particular inheritance mapping, we have to follow Mixing inheritance strategy. you can switch the mapping strategy for a particular subclass.

You can map a class hierarchy to a single table but for a particular subclass , you can switch to a separate table with foreign key mapping strategy (like a table per subclass).

We will follow the same example which we have defined in my previous post. we have only changed the xml mapping metadata file .

<hibernate-mapping package="mixing.inheritance.strategy">
<class name="CreditCardHolder" table="CREDIT_CARD_HOLDER" dynamic-insert="true" dynamic-update="true">
<id name="creditCardHolderId" column="CREDIT_CARD_HOLDER_ID" type="long">
<generator class="increment"/>
</id>
<discriminator column="DIS_CREDIT_CARD_HOLDER_VAL" type="string"/>
<property name="owner" column="OWNER"/>
 
<subclass name="CreditCardDetails" discriminator-value="CC">
<join table="CREDIT_CARD_DETAILS">
<key column="CREDIT_CARD_ID"/>
<property name="number" column="CREDIT_CARD_NUMBER"/>
<property name="expMonth" column="EXP_MONTH"/>
<property name="expYear" column="EXP_YEAR"/>
</join>
</subclass>
<subclass name="BankAccountDetails" discriminator-value="BA">
<property name="account" column="ACCOUNT_TYPE"/>
<property name="bankName" column="BANK_NAME"/>
</subclass>
</class>
</hibernate-mapping>

now, try to run the HibernateTest class and see the generated hibernate SQL statement on console.

15:13:17,057 INFO HibernateTest:20 - starting of main method
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.Environment <clinit>
INFO: Hibernate 3.0rc1
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.Environment <clinit>
INFO: hibernate.properties not found
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.Environment <clinit>
INFO: using CGLIB reflection optimizer
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.Environment <clinit>
INFO: using JDK 1.4 java.sql.Timestamp handling
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.Configuration configure
INFO: configuring from resource: /hibernate.cfg.xml
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.Configuration getConfigurationInputStream
INFO: Configuration resource: /hibernate.cfg.xml
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.Configuration addResource
INFO: Mapping resource: mixing/inheritance/strategy/CreditCardHolder.hbm.xml
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.HbmBinder bindRootPersistentClassCommonValues
INFO: Mapping class: mixing.inheritance.strategy.CreditCardHolder -> CE_CREDIT_CARD_HOLDER
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.HbmBinder bindSubclass
INFO: Mapping subclass: mixing.inheritance.strategy.CreditCardDetails -> CE_CREDIT_CARD_HOLDER
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.HbmBinder bindJoin
INFO: Mapping class join: mixing.inheritance.strategy.CreditCardDetails -> CE_CREDIT_CARD_DETAILS
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.HbmBinder bindSubclass
INFO: Mapping subclass: mixing.inheritance.strategy.BankAccountDetails -> CE_CREDIT_CARD_HOLDER
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.Configuration doConfigure
INFO: Configured SessionFactory: null
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.Configuration secondPassCompile
INFO: processing extends queue
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.Configuration secondPassCompile
INFO: processing collection mappings
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.Configuration secondPassCompile
INFO: processing association property references
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.Configuration secondPassCompile
INFO: processing foreign key constraints
Oct 16, 2012 3:13:17 PM org.hibernate.dialect.Dialect <init>
INFO: Using dialect: org.hibernate.dialect.MySQLDialect
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Maximum outer join fetch depth: 2
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Default batch fetch size: 1
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Generate SQL with comments: disabled
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Order SQL updates by primary key: disabled
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory createQueryTranslatorFactory
INFO: Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
Oct 16, 2012 3:13:17 PM org.hibernate.hql.ast.ASTQueryTranslatorFactory <init>
INFO: Using ASTQueryTranslatorFactory
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Query language substitutions: {}
Oct 16, 2012 3:13:17 PM org.hibernate.connection.C3P0ConnectionProvider configure
INFO: C3P0 using driver: null at URL: jdbc:mysql://localhost:3306/HibernateTest
Oct 16, 2012 3:13:17 PM org.hibernate.connection.C3P0ConnectionProvider configure
INFO: Connection properties: {password=****, autocommit=true, user=root}
Oct 16, 2012 3:13:17 PM org.hibernate.connection.C3P0ConnectionProvider configure
INFO: autocommit mode: true
Oct 16, 2012 3:13:17 PM org.hibernate.connection.C3P0ConnectionProvider configure
WARNING: No JDBC Driver class was specified by property hibernate.connection.driver_class
15:13:17,335 INFO MLog:80 - MLog clients using log4j logging.
15:13:17,560 INFO C3P0Registry:204 - Initializing c3p0-0.9.1.2 [built 21-May-2007 15:04:56; debug? true; trace: 10]
15:13:17,617 INFO AbstractPoolBackedDataSource:462 - Initializing c3p0 pool... com.mchange.v2.c3p0.PoolBackedDataSource@6b3054d7 [ connectionPoolDataSource -> com.mchange.v2.c3p0.WrapperConnectionPoolDataSource@78ac60c7 [ 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 -> 1bs1yqt8qt4dh851rzvoq2|107f7fe, 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@6b536310 [ description -> null, driverClass -> null, factoryClassLocation -> null, identityToken -> 1bs1yqt8qt4dh851rzvoq2|18374c9, jdbcUrl -> jdbc:mysql://localhost:3306/HibernateTest, properties -> {password=******, autocommit=true, user=******} ], preferredTestQuery -> null, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false; userOverrides: {} ], dataSourceName -> null, factoryClassLocation -> null, identityToken -> 1bs1yqt8qt4dh851rzvoq2|184e990, numHelperThreads -> 3 ]
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: JDBC batch size: 15
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: JDBC batch updates for versioned data: disabled
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Scrollable result sets: enabled
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: JDBC3 getGeneratedKeys(): enabled
Oct 16, 2012 3:13:17 PM org.hibernate.transaction.TransactionFactoryFactory buildTransactionFactory
INFO: Using default transaction strategy (direct JDBC transactions)
Oct 16, 2012 3:13:17 PM org.hibernate.transaction.TransactionManagerLookupFactory getTransactionManagerLookup
INFO: No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended)
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Automatic flush during beforeCompletion(): disabled
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Automatic session close at end of transaction: disabled
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory createCacheProvider
INFO: Cache provider: org.hibernate.cache.EhCacheProvider
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Second-level cache: enabled
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Optimize cache for minimal puts: disabled
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Structured second-level cache entries: enabled
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Query cache: disabled
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Echoing all SQL to stdout
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Statistics: disabled
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Deleted entity synthetic identifier rollback: disabled
Oct 16, 2012 3:13:17 PM org.hibernate.cfg.SettingsFactory buildSettings
INFO: Default entity-mode: pojo
Oct 16, 2012 3:13:17 PM org.hibernate.impl.SessionFactoryImpl <init>
INFO: building session factory
Oct 16, 2012 3:13:17 PM net.sf.ehcache.config.Configurator configure
WARNING: No configuration found. Configuring ehcache from ehcache-failsafe.xml found in the classpath: jar:file:/D:/Anuj/Jars/HibernateLib/ehcache-1.1.jar!/ehcache-failsafe.xml
Oct 16, 2012 3:13:18 PM org.hibernate.impl.SessionFactoryObjectFactory addInstance
INFO: Not binding factory to JNDI, no JNDI name configured
Oct 16, 2012 3:13:18 PM org.hibernate.dialect.Dialect <init>
INFO: Using dialect: org.hibernate.dialect.MySQLDialect
Oct 16, 2012 3:13:18 PM org.hibernate.cfg.Configuration secondPassCompile
INFO: processing extends queue
Oct 16, 2012 3:13:18 PM org.hibernate.cfg.Configuration secondPassCompile
INFO: processing collection mappings
Oct 16, 2012 3:13:18 PM org.hibernate.cfg.Configuration secondPassCompile
INFO: processing association property references
Oct 16, 2012 3:13:18 PM org.hibernate.cfg.Configuration secondPassCompile
INFO: processing foreign key constraints
Oct 16, 2012 3:13:18 PM org.hibernate.cfg.Configuration secondPassCompile
INFO: processing extends queue
Oct 16, 2012 3:13:18 PM org.hibernate.cfg.Configuration secondPassCompile
INFO: processing collection mappings
Oct 16, 2012 3:13:18 PM org.hibernate.cfg.Configuration secondPassCompile
INFO: processing association property references
Oct 16, 2012 3:13:18 PM org.hibernate.cfg.Configuration secondPassCompile
INFO: processing foreign key constraints
Oct 16, 2012 3:13:18 PM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: Running hbm2ddl schema export
Oct 16, 2012 3:13:18 PM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: exporting generated schema to database
Oct 16, 2012 3:13:18 PM org.hibernate.connection.C3P0ConnectionProvider configure
INFO: C3P0 using driver: null at URL: jdbc:mysql://localhost:3306/HibernateTest
Oct 16, 2012 3:13:18 PM org.hibernate.connection.C3P0ConnectionProvider configure
INFO: Connection properties: {password=****, autocommit=true, user=root}
Oct 16, 2012 3:13:18 PM org.hibernate.connection.C3P0ConnectionProvider configure
INFO: autocommit mode: true
Oct 16, 2012 3:13:18 PM org.hibernate.connection.C3P0ConnectionProvider configure
WARNING: No JDBC Driver class was specified by property hibernate.connection.driver_class
15:13:18,239 INFO AbstractPoolBackedDataSource:462 - Initializing c3p0 pool... com.mchange.v2.c3p0.PoolBackedDataSource@5f720ff0 [ connectionPoolDataSource -> com.mchange.v2.c3p0.WrapperConnectionPoolDataSource@5f671008 [ 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 -> 1bs1yqt8qt4dh851rzvoq2|c19fb, 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@8d7cdaa2 [ description -> null, driverClass -> null, factoryClassLocation -> null, identityToken -> 1bs1yqt8qt4dh851rzvoq2|c15a3f, jdbcUrl -> jdbc:mysql://localhost:3306/HibernateTest, properties -> {password=******, autocommit=true, user=******} ], preferredTestQuery -> null, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false; userOverrides: {} ], dataSourceName -> null, factoryClassLocation -> null, identityToken -> 1bs1yqt8qt4dh851rzvoq2|b83bd, numHelperThreads -> 3 ]
Oct 16, 2012 3:13:18 PM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: schema export complete
Oct 16, 2012 3:13:18 PM org.hibernate.impl.SessionFactoryImpl checkNamedQueries
INFO: Checking 0 named queries
Hibernate: insert into CE_CREDIT_CARD_HOLDER (OWNER, DIS_CREDIT_CARD_HOLDER_VAL, CREDIT_CARD_HOLDER_ID) values (?, 'CC', ?)
Hibernate: insert into CE_CREDIT_CARD_DETAILS (CREDIT_CARD_NUMBER, EXP_MONTH, EXP_YEAR, CREDIT_CARD_ID) values (?, ?, ?, ?)
Hibernate: insert into CE_CREDIT_CARD_HOLDER (OWNER, ACCOUNT_TYPE, BANK_NAME, DIS_CREDIT_CARD_HOLDER_VAL, CREDIT_CARD_HOLDER_ID) values (?, ?, ?, 'BA', ?)
Oct 16, 2012 3:13:18 PM org.hibernate.impl.SessionFactoryImpl close
INFO: closing

let's run the polymorphic query against CreditCardHolder class
   Query query = session.createQuery("from CreditCardHolder");
   List list = query.list();

It generates This SQL statement :

Hibernate: 
select creditcard0_.CREDIT_CARD_HOLDER_ID as CREDIT1_, 
creditcard0_.OWNER as OWNER0_, 
creditcard0_.ACCOUNT_TYPE as ACCOUNT4_0_, 
creditcard0_.BANK_NAME as BANK5_0_, 
creditcard0_1_.CREDIT_CARD_NUMBER as CREDIT2_1_, 
creditcard0_1_.EXP_MONTH as EXP3_1_, 
creditcard0_1_.EXP_YEAR as EXP4_1_, 
creditcard0_.DIS_CREDIT_CARD_HOLDER_VAL as DIS2_ 
from 
CE_CREDIT_CARD_HOLDER creditcard0_ 
left outer join CE_CREDIT_CARD_DETAILS creditcard0_1_ 
on creditcard0_.CREDIT_CARD_HOLDER_ID=creditcard0_1_.CREDIT_CARD_ID

If your class hierarchy is wide that time, outer join can be a major issue for this type of strategy. Than you have to switch different fetching strategy which execute a immediate SQL SELECT statement instead of outer join.

see the xml mapping metadata again,

<hibernate-mapping package="mixing.inheritance.strategy">
<class name="CreditCardHolder" table="CREDIT_CARD_HOLDER" dynamic-insert="true" dynamic-update="true">
<id name="creditCardHolderId" column="CREDIT_CARD_HOLDER_ID" type="long">
<generator class="increment"/>
</id>
<discriminator column="DIS_CREDIT_CARD_HOLDER_VAL"/>
<property name="owner" column="OWNER"/>
 
<subclass name="CreditCardDetails" discriminator-value="CC">
<join table="CREDIT_CARD_DETAILS" fetch="select">
<key column="CREDIT_CARD_ID"/>
<property name="number" column="CREDIT_CARD_NUMBER"/>
<property name="expMonth" column="EXP_MONTH"/>
<property name="expYear" column="EXP_YEAR"/>
</join>
</subclass>
<subclass name="BankAccountDetails" discriminator-value="BA">
<property name="account" column="ACCOUNT_TYPE"/>
<property name="bankName" column="BANK_NAME"/>
</subclass>
</class>
</hibernate-mapping>