Table Per Concrete Class + Unions
Continuing with the inheritance mechanisms, I shall now attempt to implement the second approach. This approach tries to overcome the drawbacks of the first technique.
In this technique
Also I executed an HQL query to return the footballer with name Tom.
Update: For a brief summary of the Hibernate Inheritance types check this post.
Continuing with the inheritance mechanisms, I shall now attempt to implement the second approach. This approach tries to overcome the drawbacks of the first technique.
In this technique
- The abstract class is also mapped into Hibernate.
- The common properties are mapped inside this class.
- The concrete classes representing the tables are then mapped using the union-subclass attribute
- The attributes specific to the concrete implementations are mapped here.
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.inheritance.model"> <class name="SportsPerson" abstract="true"> <id name="id" type="long"> <column name="ID" /> <generator class="identity" /> </id> <property name="name" type="string"> <column name="NAME" /> </property> <union-subclass name="Cricketer" table="CRICKETER"> <property name="runs" type="integer"> <column name="RUNS" /> </property> <property name="wickets" type="integer"> <column name="WICKETS" /> </property> <property name="t20Player" type="boolean"> <column name="T20_PLAYER" /> </property> </union-subclass> <union-subclass name="Footballer" table="FOOTBALLER"> <property name="goals" type="integer"> <column name="GOALS" /> </property> <property name="appearances" type="integer"> <column name="APPEARANCES" /> </property> <property name="sendOffs" type="integer"> <column name="SEND_OFFS" /> </property> </union-subclass> </class> </hibernate-mapping>
As can be seen, the SportsPerson class is mapped as an abstract class with the two concrete implementations being mapped within it. The base class attributes have been placed within the <class> element. The properties specific to the Concrete class are mapped inside the <union-subclass> element.
On server start up the logs(cleaned) are as below:
On server start up the logs(cleaned) are as below:
Exception in thread "main" org.hibernate.MappingException: Cannot use identity column key generation with <union-subclass> mapping for: com.inheritance.model.SportsPerson at org.hibernate.persister.entity.UnionSubclassEntityPersister.<init>(UnionSubc lassEntityPersister.java:67) at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFacto ry.java:61) at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:226) at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1294) at test.inheritance.approach2.mapping.TestApproach2.main(TestApproach2.java:48)
Hibernate does not allow the use of identity column (auto increment field) when using union-subclass. For a more detailed explanation refer this link. I modified the generator class to hilo.
<class name="SportsPerson" abstract="true"> <id name="id" type="long"> <column name="ID" /> <generator class="hilo" /> </id>
I turned on the auto-create property of Hibernate.The start up logs are now as below:
359 [main] DEBUG org.hibernate.cfg.Configuration - null<-org.dom4j.tree.Defaul tAttribute@183f74d [Attribute: name resource value "com/inheritance/approach2/ma pping/SportsPerson.hbm.xml"] ... 765 [main] INFO org.hibernate.cfg.HbmBinder - Mapping class: com.inheritance. model.SportsPerson -> SportsPerson 781 [main] DEBUG org.hibernate.cfg.HbmBinder - Mapped property: id -> ID 812 [main] DEBUG org.hibernate.cfg.HbmBinder - Mapped property: name -> NAME 1000 [main] INFO org.hibernate.cfg.HbmBinder - Mapping union-subclass: com.inh eritance.model.Cricketer -> CRICKETER 1000 [main] DEBUG org.hibernate.cfg.HbmBinder - Mapped property: runs -> RUNS 1000 [main] DEBUG org.hibernate.cfg.HbmBinder - Mapped property: wickets -> WIC KETS 1000 [main] DEBUG org.hibernate.cfg.HbmBinder - Mapped property: t20Player -> T 20_PLAYER 1000 [main] INFO org.hibernate.cfg.HbmBinder - Mapping union-subclass: com.inh eritance.model.Footballer -> FOOTBALLER 1000 [main] DEBUG org.hibernate.cfg.HbmBinder - Mapped property: goals -> GOALS 1000 [main] DEBUG org.hibernate.cfg.HbmBinder - Mapped property: appearances -> APPEARANCES 1000 [main] DEBUG org.hibernate.cfg.HbmBinder - Mapped property: sendOffs -> SE ND_OFFS 3203 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Stat ic SQL for entity: com.inheritance.model.SportsPerson 3203 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Ver sion select: select ID from SportsPerson where ID =? 3203 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Sna pshot select: select sportspers_.ID, sportspers_.NAME as NAME0_ from ( select T2 0_PLAYER, ID, null as GOALS, NAME, null as APPEARANCES, RUNS, null as SEND_OFFS, WICKETS, 1 as clazz union select null as T20_PLAYER, ID, GOALS, NAME, APPEARANCES, null as RUNS, SEND_OFFS, null as WICKETS, 2 as clazz_ from F OOTBALLER ) sportspers_ where sportspers_.ID=? 3203 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Ins ert 0: insert into SportsPerson (NAME, ID) values (?, ?) 3203 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Upd ate 0: update SportsPerson set NAME=? where ID=? 3203 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Del ete 0: delete from SportsPerson where ID=? 3218 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Stat ic SQL for entity: com.inheritance.model.Cricketer 3218 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Ver sion select: select ID from CRICKETER where ID =? 3218 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Sna pshot select: select cricketer_.ID, cricketer_.NAME as NAME0_, cricketer_.RUNS a s RUNS1_, cricketer_.WICKETS as WICKETS1_, cricketer_.T20_PLAYER as T3_1_ from C RICKETER cricketer_ where cricketer_.ID=? 3218 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Ins ert 0: insert into CRICKETER (NAME, RUNS, WICKETS, T20_PLAYER, ID) values (?, ?, ?, ?, ?) 3218 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Upd ate 0: update CRICKETER set NAME=?, RUNS=?, WICKETS=?, T20_PLAYER=? where ID=? 3218 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Del ete 0: delete from CRICKETER where ID=? 3250 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Stat ic SQL for entity: com.inheritance.model.Footballer 3250 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Ver sion select: select ID from FOOTBALLER where ID =? 3250 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Sna pshot select: select footballer_.ID, footballer_.NAME as NAME0_, footballer_.GOA LS as GOALS2_, footballer_.APPEARANCES as APPEARAN2_2_, footballer_.SEND_OFFS as SEND3_2_ from FOOTBALLER footballer_ where footballer_.ID=? 3250 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Ins ert 0: insert into FOOTBALLER (NAME, GOALS, APPEARANCES, SEND_OFFS, ID) values ( ?, ?, ?, ?, ?) 3250 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Upd ate 0: update FOOTBALLER set NAME=?, GOALS=?, APPEARANCES=?, SEND_OFFS=? where I D=? 3250 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Del ete 0: delete from FOOTBALLER where ID=? 3359 [main] DEBUG org.hibernate.loader.entity.EntityLoader - Static select for entity com.inheritance.model.SportsPerson: select sportspers0_.ID as ID0_0_, spo rtspers0_.NAME as NAME0_0_, sportspers0_.RUNS as RUNS1_0_, sportspers0_.WICKETS as WICKETS1_0_, sportspers0_.T20_PLAYER as T3_1_0_, sportspers0_.GOALS as GOALS2 _0_, sportspers0_.APPEARANCES as APPEARAN2_2_0_, sportspers0_.SEND_OFFS as SEND3 _2_0_, sportspers0_.clazz_ as clazz_0_ from ( select T20_PLAYER, ID, null as GOA LS, NAME, null as APPEARANCES, RUNS, null as SEND_OFFS, WICKETS, 1 as clazz_ fro m CRICKETER union select null as T20_PLAYER, ID, GOALS, NAME, APPEARANCES, null as RUNS, SEND_OFFS, null as WICKETS, 2 as clazz_ from FOOTBALLER ) sportspers0_ where sportspers0_.ID=? for update 3390 [main] DEBUG org.hibernate.loader.entity.EntityLoader - Static select for action ACTION_MERGE on entity com.inheritance.model.SportsPerson: select sportsp ers0_.ID as ID0_0_, sportspers0_.NAME as NAME0_0_, sportspers0_.RUNS as RUNS1_0_ , sportspers0_.WICKETS as WICKETS1_0_, sportspers0_.T20_PLAYER as T3_1_0_, sport spers0_.GOALS as GOALS2_0_, sportspers0_.APPEARANCES as APPEARAN2_2_0_, sportspe rs0_.SEND_OFFS as SEND3_2_0_, sportspers0_.clazz_ as clazz_0_ from ( select T20_ PLAYER, ID, null as GOALS, NAME, null as APPEARANCES, RUNS, null as SEND_OFFS, W ICKETS, 1 as clazz_ from CRICKETER union select null as T20_PLAYER, ID, GOALS, N AME, APPEARANCES, null as RUNS, SEND_OFFS, null as WICKETS, 2 as clazz_ from FOO TBALLER ) sportspers0_ where sportspers0_.ID=? 3390 [main] DEBUG org.hibernate.loader.entity.EntityLoader - Static select for entity com.inheritance.model.Cricketer: select cricketer0_.ID as ID0_0_, cricket er0_.NAME as NAME0_0_, cricketer0_.RUNS as RUNS1_0_, cricketer0_.WICKETS as WICK ETS1_0_, cricketer0_.T20_PLAYER as T3_1_0_ from CRICKETER cricketer0_ where cric keter0_.ID=?
...[Other Cricketer Table queries for CRUD, MERGE and Refresh] 3390 [main] DEBUG org.hibernate.loader.entity.EntityLoader - Static select for entity com.inheritance.model.Footballer: select footballer0_.ID as ID0_0_, footb aller0_.NAME as NAME0_0_, footballer0_.GOALS as GOALS2_0_, footballer0_.APPEARAN CES as APPEARAN2_2_0_, footballer0_.SEND_OFFS as SEND3_2_0_ from FOOTBALLER foot baller0_ where footballer0_.ID=? 3390 [main] DEBUG org.hibernate.loader.entity.EntityLoader - Static select for action ACTION_MERGE on entity com.inheritance.model.Footballer: select footballe r0_.ID as ID0_0_, footballer0_.NAME as NAME0_0_, footballer0_.GOALS as GOALS2_0_ , footballer0_.APPEARANCES as APPEARAN2_2_0_, footballer0_.SEND_OFFS as SEND3_2_ 0_ from FOOTBALLER footballer0_ where footballer0_.ID=?
...[Other Footballer Table queries for CRUD, MERGE and Refresh] 3453 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport - drop table if exists CRICKETER 3578 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport - drop table if exists FOOTBALLER 3640 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport - drop table if exists hibernate_unique_key 3703 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport - create table CRICKETER ( ID bigint not null, NAME varchar(255), RUNS integer, WICKETS integer, T20_PLAYER bit, primary key (ID) ) 3797 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport - create table FOOTBALLER ( ID bigint not null, NAME varchar(255), GOALS integer, APPEARANCES integer, SEND_OFFS integer, primary key (ID) ) 3797 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport - create table hibernate_unique_key ( next_hi integer ) 3828 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport - insert into hibernate_unique_key values (0) 3828 [main] INFO org.hibernate.tool.hbm2ddl.SchemaExport - schema export compl ete
From the huge list of queries generated it can be seen that queries have been generated for the abstract class and each of the concrete sub-classes too. I now execute the code to create a cricketer:
private static void createCricketer() { Cricketer crickter = new Cricketer(); crickter.setName("Rahul Dravid"); crickter.setRuns(12000); crickter.setT20Player(false); crickter.setWickets(2); Session session = sessionFactory.openSession(); Transaction t = session.beginTransaction(); session.save(crickter); t.commit(); }
The generated logs show the below query being fired
3203 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedSt
atement (open PreparedStatements: 0, globally: 0)
3203 [main] DEBUG org.hibernate.SQL -
insert
into
CRICKETER
(NAME, RUNS, WICKETS, T20_PLAYER, ID)
values
(?, ?, ?, ?, ?)
Also I executed an HQL query to return the footballer with name Tom.
private static void getFootballerWithName() { Session session = sessionFactory.openSession(); try { Query query = session.createQuery("from Footballer f where f.name like 'Tom%'"); System.out.println("The Player is " + ((Footballer)query.uniqueResult()).getName()); } catch (HibernateException e) { e.printStackTrace(); } finally { session.close(); } }
The logs are as below
3453 [main] DEBUG org.hibernate.SQL - select footballer0_.ID as ID0_, footballer0_.NAME as NAME0_, footballer0_.GOALS as GOALS2_, footballer0_.APPEARANCES as APPEARAN2_2_, footballer0_.SEND_OFFS as SEND3_2_ from FOOTBALLER footballer0_ where footballer0_.NAME like 'Tom%' The Player is Tom Cleaverly 3547 [main] DEBUG org.hibernate.impl.SessionImpl - closing session
The generated query was directly on the Footballer entity. Finally I decided to fetch the records of all sportsperson in the system.
private static void getAllSportsPerson() { Session session = sessionFactory.openSession(); try { Query query = session.createQuery("from SportsPerson"); @SuppressWarnings("unchecked") final List<SportsPerson> sportsPersons = query.list(); System.out.println("Total Records : " + sportsPersons.size()); for (SportsPerson sportsPerson : sportsPersons) { System.out.println("Id: " + sportsPerson.getId()); System.out.println("Name: " + sportsPerson.getName()); if (sportsPerson instanceof Cricketer) { Cricketer cricketer = (Cricketer) sportsPerson; System.out.println("Sport - Cricket"); System.out.println("Runs Scored: " + cricketer.getRuns()); System.out.println("Wickets taken : " + cricketer.getWickets()); System.out.println("T20 Player: " + cricketer.getT20Player()); } else if (sportsPerson instanceof Footballer) { Footballer footballer = (Footballer) sportsPerson; System.out.println("Sport - Football"); System.out.println("Goals Scored: " + footballer.getGoals()); System.out.println("Appearances : " + footballer.getAppearances()); System.out.println("Send Offs: " + footballer.getSendOffs()); } } } catch (HibernateException e) { e.printStackTrace(); } finally { session.close(); } }
On executing the code a single query was executed which fetched the records from all the sub-classes:
2703 [main] DEBUG org.hibernate.SQL - select sportspers0_.ID as ID0_, sportspers0_.NAME as NAME0_, sportspers0_.RUNS as RUNS1_, sportspers0_.WICKETS as WICKETS1_, sportspers0_.T20_PLAYER as T3_1_, sportspers0_.GOALS as GOALS2_, sportspers0_.APPEARANCES as APPEARAN2_2_, sportspers0_.SEND_OFFS as SEND3_2_, sportspers0_.clazz_ as clazz_ from ( select T20_PLAYER, ID, null as GOALS, NAME, null as APPEARANCES, RUNS, null as SEND_OFFS, WICKETS, 1 as clazz_ from CRICKETER union select null as T20_PLAYER, ID, GOALS, NAME, APPEARANCES, null as RUNS, SEND_OFFS, null as WICKETS, 2 as clazz_ from FOOTBALLER ) sportspers0_ 2719 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - preparing statement ... 2797 [main] DEBUG org.hibernate.loader.Loader - result row: EntityKey[com.inher itance.model.SportsPerson#1] 2797 [main] DEBUG org.hibernate.type.IntegerType - returning '1' as column: cla zz_ 2797 [main] DEBUG org.hibernate.loader.Loader - Initializing object from Result Set: [com.inheritance.model.Cricketer#1] 2828 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Hydr ating entity: [com.inheritance.model.Cricketer#1] 2828 [main] DEBUG org.hibernate.type.StringType - returning 'Rahul Dravid' as c olumn: NAME0_ ...
2828 [main] DEBUG org.hibernate.loader.Loader - result row: EntityKey[com.inher itance.model.SportsPerson#32768] 2828 [main] DEBUG org.hibernate.type.IntegerType - returning '2' as column: cla zz_ 2828 [main] DEBUG org.hibernate.loader.Loader - Initializing object from Result Set: [com.inheritance.model.Footballer#32768] 2828 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Hydr ating entity: [com.inheritance.model.Footballer#32768] 2844 [main] DEBUG org.hibernate.type.StringType - returning 'Tom Cleaverly' as column: NAME0_ 2844 [main] DEBUG org.hibernate.type.IntegerType - returning '3' as column: GOA LS2_ 2844 [main] DEBUG org.hibernate.type.IntegerType - returning '5' as column: APP EARAN2_2_ 2844 [main] DEBUG org.hibernate.type.IntegerType - returning '0' as column: SEN D3_2_ Total Records : 2 Id: 1 Name: Rahul Dravid Sport - Cricket Runs Scored: 12000 Wickets taken : 2 T20 Player: false Id: 32768 Name: Tom Cleaverly Sport - Football Goals Scored: 3 Appearances : 5 Send Offs: 0
2844 [main] DEBUG org.hibernate.impl.SessionImpl - closing session
Hibernate executed a single query using a sub query in the form clause. it also added a returned value CLAZZ to help distinguish between the appropriate sub-classes. Based on this value for each of the returned row in the result set, the Hibernate Loader accordingly created appropriate objects of the subclass.
The outer select clause combines all the fields of all the sub-classes. Thus null padding has been applied in the inner queries based on the different properties present in each of the sub-class. Thus we have managed to solve the issue of polymorphic queries.
It is now possible to implement polymorphic associations correctly without any duplications.
I decided that every Sportsperson must have an address.
Property duplication has also been avoided.
Thus the disadvantages observed in approach 1 are eliminated here.
At the same time the sub-classes still retain their identity.
The outer select clause combines all the fields of all the sub-classes. Thus null padding has been applied in the inner queries based on the different properties present in each of the sub-class. Thus we have managed to solve the issue of polymorphic queries.
It is now possible to implement polymorphic associations correctly without any duplications.
I decided that every Sportsperson must have an address.
public class Address { private Long id; private String city; private SportsPerson sportsPerson; //setter getters }The Address class has a polymorphic association to SportsPerson class. It is not directly aware of the sports details as in Cricketer or Footballer. Like a good object it is only concerned with the generic SportsPerson class. The hbm file for the same is :
<?xml version ="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.inheritance.model"> <class name="Address" table="ADDRESS"> <id name="id" type="long"> <column name="ID" /> <generator class="native" /> </id> <property name="city" type="string"> <column name="CITY" /> </property> <many-to-one name="sportsPerson" class="SportsPerson" column="sp_id" foreign-key="address_fk1" not-null="true" /> </class> </hibernate-mapping>The DDL created for this table is as below:
create table ADDRESS ( ID bigint not null auto_increment, CITY varchar(255), sp_id bigint not null, primary key (ID) )As can be seen the foreign key was not applied here. This is simply because there is no table for Sportsperson. This is a disadvantage of the technique - certain SQL constraints will not work because the abstract class has no representation in the database. I also wrote a code to create a Cricketer with an address.
public static void createCricketerWithAddress() { Cricketer cricketer = new Cricketer(); cricketer.setName("Rahul Dravid"); cricketer.setRuns(12000); cricketer.setT20Player(false); cricketer.setWickets(2); Address address = new Address(); address.setCity("Bangalore"); address.setSportsPerson(cricketer); Session session = sessionFactory.openSession(); Transaction t = session.beginTransaction(); session.save(cricketer); session.save(address); t.commit(); }The fired SQL is :
2766 [main] DEBUG org.hibernate.SQL - insert into CRICKETER (NAME, RUNS, WICKETS, T20_PLAYER, ID) values (?, ?, ?, ?, ?) 2781 [main] DEBUG org.hibernate.SQL - insert into ADDRESS (CITY, sp_id) values (?, ?)As can be seen, the code worked fine. Now what if I want all sportsperson residing in Bangalore ?
public static void getSportsPersonWithAddress() { Session session = sessionFactory.openSession(); try { Query query = session.createQuery("select sp from SportsPerson sp " +
",Address a where a.city like 'Ba%'"); final List<SportsPerson> sportsPersons = query.list(); for (SportsPerson sportsPerson : sportsPersons) { System.out.println("Id: " + sportsPerson.getId()); System.out.println("Name: " + sportsPerson.getName()); System.out.println("class is " + sportsPerson.getClass()); } } catch (HibernateException e) { e.printStackTrace(); } finally { session.close(); } }The generated SQL is :
3219 [main] DEBUG org.hibernate.SQL - select sportspers0_.ID as ID0_, sportspers0_.NAME as NAME0_, sportspers0_.RUNS as RUNS1_, sportspers0_.WICKETS as WICKETS1_, sportspers0_.T20_PLAYER as T3_1_, sportspers0_.GOALS as GOALS2_, sportspers0_.APPEARANCES as APPEARAN2_2_, sportspers0_.SEND_OFFS as SEND3_2_, sportspers0_.clazz_ as clazz_ from ( select T20_PLAYER, ID, null as GOALS, NAME, null as APPEARANCES, RUNS, null as SEND_OFFS, WICKETS, 1 as clazz_ from CRICKETER union select null as T20_PLAYER, ID, GOALS, NAME, APPEARANCES, null as RUNS, SEND_OFFS, null as WICKETS, 2 as clazz_ from FOOTBALLER ) sportspers0_, ADDRESS address1_ where address1_.CITY like 'Ba%' Id: 1 Name: Rahul Dravid class is class com.inheritance.model.CricketerThe query generated is similar to the earlier polymorphic query. The inner query simply does the union of the two tables. It is on this result set that the where clause is applied. Thus polymorphic associations is possible here.
Property duplication has also been avoided.
Thus the disadvantages observed in approach 1 are eliminated here.
At the same time the sub-classes still retain their identity.
public static void getFootballerWithName() { Session session = sessionFactory.openSession(); try { Query query = session.createQuery("from Footballer f where f.name like 'Tom%'"); System.out.println("The Player is " + ((Footballer)query.uniqueResult()).getName()); } catch (HibernateException e) { e.printStackTrace(); } finally { session.close(); } }The logs are as below:
3093 [main] DEBUG org.hibernate.engine.query.QueryPlanCache - located HQL query plan in cache (from Footballer f where f.name like 'Tom%') Hibernate: select footballer0_.ID as ID0_, footballer0_.NAME as NAME0_, footballer0_.GOALS as GOALS2_, footballer0_.APPEARANCES as APPEARAN2_2_, footballer0_.SEND_OFFS as SEND3_2_ from FOOTBALLER footballer0_ where footballer0_.NAME like 'Tom%'
Update: For a brief summary of the Hibernate Inheritance types check this post.
you said that "certain SQL constraints will not work because the abstract class has no representation in the database" ... like what ?? can you give some examples
ReplyDeleteHi,
ReplyDeleteIn the post you can see the Address-SportsPerson relation. Every address is associated with a Sportsperson. What this means is that there is need for column representing SportsPerson to have a foreign key constraint.
But how to apply this constraint? Should it be in Cricketer table or Footballer table?
This is the problem.