- This topic has 4 replies, 2 voices, and was last updated 13 years, 5 months ago by hoteagle.
-
AuthorPosts
-
hoteagleMember“Hibernate RE” in the title means Hibernate Reverse Engineer.
I just build a small demo to test the Hibernate Reverse Engineer’s results. I mostly follows the steps in the tutorial for “Hibernate & Spring” at http://www.myeclipseide.com/documentation/quickstarts/hibernateandspring/.
I changed the sample a little with two tables contains foreign key.
I find errors during just a simple queryByName search based on the generated DAO&POJO. It seems like getHibernateTemplate().find cannot correctly return a List<Entity> where Entity is a POJO generated by Hibernate Reverse Engineer.
Since Foreign key constrain is very common in DB and this might be a critical problem for Hibernate Reverse Engineering if my usage is not wrong.I bought the MyEclipse for Spring and using version 8.6 and 9.0 both on MAC os 10.6.7. I use Hibernate 3.3 and Spring 3.0 in the project below. DB used MySql (version > 5.0). No annotation used.
The detailed descriptions:
The difference is that I create two tables with a simple foreign key constrain. In the following two tables, the entity contains a ‘Type’ which is mapped as many-to-one to “etype” in table codeentitytype
DROP TABLE IF EXISTS `codeentitytype`; CREATE TABLE `codeentitytype` ( `code` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT '', `etype` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`code`), UNIQUE KEY `etype` (`etype`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; DROP TABLE IF EXISTS `entity`; CREATE TABLE `entity` ( `EntityID` int(11) NOT NULL AUTO_INCREMENT, `Name` varchar(200) DEFAULT NULL, `Type` varchar(50) DEFAULT NULL, PRIMARY KEY (`EntityID`), KEY `Name` (`Name`), KEY `Type` (`Type`), CONSTRAINT `entity_ibfk_1` FOREIGN KEY (`Type`) REFERENCES `codeentitytype` (`etype`) ON DELETE NO ACTION ON UPDATE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
Then I write a simple query.
// BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); ApplicationContext ctx = new ClassPathXmlApplicationContext ("applicationContext.xml"); Persistence persistenceLayer = (Persistence) ctx.getBean("persistence"); List<Entity> entLst = persistenceLayer.findEntityByName("dna1"); ListIterator<Entity> iter = entLst.listIterator(); while(iter.hasNext()){ Entity ent = iter.next(); Integer id = ent.getEntityId(); System.out.println("Find entity with name as " + name + " with id = " + id); }
Then it comes with the following errors. It seems query is done but error happens during translate the rows obtained back to POJO Class like “Entity”. The Entity class generated by Hibernate reverse engineer contains a property like “private Codeentitytype codeentitytype;” but not “String Type“, which is due to the foreign key definition.
I guess the error might due to some mismatch between the returned String like ‘DNA’ in the row found by getHibernateTemplate().find and the properties in Entity as Codeentitytype codeentitytype. Note that the first property in Class Codeentitytype is “Integer code”, which is int type.Exception in thread “main” org.springframework.dao.TransientDataAccessResourceException: Hibernate operation: could not execute query; SQL [select entity0_.EntityID as EntityID0_, entity0_.Type as Type0_, entity0_.Name as Name0_ from FKDemo.entity entity0_ where entity0_.Name=?]; Invalid value for getInt() – ‘DNA’; nested exception is java.sql.SQLException: Invalid value for getInt() – ‘DNA’
at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:107)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at org.springframework.orm.hibernate3.HibernateAccessor.convertJdbcAccessException(HibernateAccessor.java:424)
at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:410)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:411)
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
at org.springframework.orm.hibernate3.HibernateTemplate.find(HibernateTemplate.java:912)
at org.springframework.orm.hibernate3.HibernateTemplate.find(HibernateTemplate.java:908)
at hibernate.EntityDAO.findByProperty(EntityDAO.java:84)
at hibernate.EntityDAO.findByName(EntityDAO.java:92)
at hibernate.Persistence.findEntityByName(Persistence.java:17)
at hibernate.Logic.main(Logic.java:25)
Caused by: java.sql.SQLException: Invalid value for getInt() – ‘DNA’
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:987)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:982)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927)
at com.mysql.jdbc.ResultSetImpl.getInt(ResultSetImpl.java:2725)
at com.mysql.jdbc.ResultSetImpl.getInt(ResultSetImpl.java:2813)
at org.hibernate.type.IntegerType.get(IntegerType.java:51)
at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:184)
at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:173)
at org.hibernate.type.ManyToOneType.hydrate(ManyToOneType.java:126)
at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2114)
at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1404)
at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1332)
at org.hibernate.loader.Loader.getRow(Loader.java:1230)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:603)
at org.hibernate.loader.Loader.doQuery(Loader.java:724)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
at org.hibernate.loader.Loader.doList(Loader.java:2232)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2129)
at org.hibernate.loader.Loader.list(Loader.java:2124)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:401)
at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:363)
at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:196)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1149)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
at org.springframework.orm.hibernate3.HibernateTemplate$30.doInHibernate(HibernateTemplate.java:921)
at org.springframework.orm.hibernate3.HibernateTemplate$30.doInHibernate(HibernateTemplate.java:1)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
… 7 moreIn order to prove my guess, I faked the table a little to change the “Integer code” property to be as “String code” which is no more as “int” type. The changed table is like:
DROP TABLE IF EXISTS `codeentitytype`; CREATE TABLE `codeentitytype` ( `code` varchar(255) NOT NULL, `name` varchar(255) DEFAULT '', `etype` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`code`), UNIQUE KEY `etype` (`etype`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; DROP TABLE IF EXISTS `entity`; CREATE TABLE `entity` ( `EntityID` int(11) NOT NULL AUTO_INCREMENT, `Name` varchar(200) DEFAULT NULL, `Type` varchar(50) DEFAULT NULL, PRIMARY KEY (`EntityID`), KEY `Name` (`Name`), KEY `Type` (`Type`), CONSTRAINT `entity_ibfk_1` FOREIGN KEY (`Type`) REFERENCES `codeentitytype` (`etype`) ON DELETE NO ACTION ON UPDATE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
Then the original simple query codes will pass with correct result (one entity id is found and printed). However, it doesn’t mean the problem is gone. Just try to print more about the Codeentitytype type and it will report error again.
List<Entity> entLst = persistenceLayer.findEntityByName(name); ListIterator<Entity> iter = entLst.listIterator(); while(iter.hasNext()){ Entity ent = iter.next(); Integer id = ent.getEntityId(); Codeentitytype type = ent.getCodeentitytype(); System.out.println("Find entity with name as " + name + " with id = " + id + " type = " + type.getEtype() ); }
The error below shows that it might try to use the String “DNA” found within the return row to match with the “Codeentitytype” but failed.
Exception in thread “main” org.springframework.orm.hibernate3.HibernateObjectRetrievalFailureException: No row with the given identifier exists: [hibernate.Codeentitytype#DNA]; nested exception is org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [hibernate.Codeentitytype#DNA]
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:663)
at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:411)
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
at org.springframework.orm.hibernate3.HibernateTemplate.find(HibernateTemplate.java:912)
at org.springframework.orm.hibernate3.HibernateTemplate.find(HibernateTemplate.java:908)
at hibernate.EntityDAO.findByProperty(EntityDAO.java:84)
at hibernate.EntityDAO.findByName(EntityDAO.java:92)
at hibernate.Persistence.findEntityByName(Persistence.java:17)
at hibernate.Logic.main(Logic.java:25)
Caused by: org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [hibernate.Codeentitytype#DNA]
at org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:419)
at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:171)
at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:207)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:126)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:906)
at org.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:874)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:590)
at org.hibernate.type.EntityType.resolve(EntityType.java:412)
at org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:139)
at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:877)
at org.hibernate.loader.Loader.doQuery(Loader.java:752)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
at org.hibernate.loader.Loader.doList(Loader.java:2232)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2129)
at org.hibernate.loader.Loader.list(Loader.java:2124)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:401)
at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:363)
at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:196)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1149)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
at org.springframework.orm.hibernate3.HibernateTemplate$30.doInHibernate(HibernateTemplate.java:921)
at org.springframework.orm.hibernate3.HibernateTemplate$30.doInHibernate(HibernateTemplate.java:1)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
… 7 morePlease help me on this issue. I have lots of table with some foreign keys defined and wish to depend on Hibernate’s Reverse Engineering ability to manage it.[/list]
BTW, I also tried with tables w/o foreign key and the whole story above works well. So the errors are most possibly caused by foreign key.
The Installation infomation:
- *** Date:
Thursday, April 14, 2011 2:16:38 AM CDT** System properties:
OS=MacOSX
OS version=10.6.7
Java version=1.6.0_24*** MyEclipse details:
MyEclipse Enterprise Workbench
Version: 8.6.1
Build id: 8.6.1-20101117*** Eclipse details:
MyEclipse for SpringVersion: 8.6
Eclipse startup command=-os
macosx
-ws
carbon
-arch
x86
-showsplash
-launcher
/Library/Genuitec/MyEclipse for Spring 8.6/myeclipseforspring.app/Contents/MacOS/myeclipseforspring
-name
Myeclipseforspring
–launcher.library
/Library/Genuitec/MyEclipse for Spring 8.6/myeclipseforspring.app/Contents/MacOS//../../../../Common/plugins/org.eclipse.equinox.launcher.carbon.macosx_1.0.200.v20090520-1835/eclipse_1206.so
-startup
/Library/Genuitec/MyEclipse for Spring 8.6/myeclipseforspring.app/Contents/MacOS/../../../../Common/plugins/org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar
-install
/Library/Genuitec/MyEclipse for Spring 8.6
-configuration
../../../configuration
-keyring
/Users/hoteagle/.eclipse_keyring
-consoleLog
-showlocation
-vm
/System/Library/Frameworks/JavaVM.framework
hoteagleMemberThe Persistence Class is like
package hibernate; import java.util.List; public class Persistence { private EntityDAO entityDAO; public EntityDAO getEntityDAO() { return entityDAO; } public void setEntityDAO(EntityDAO entityDAO) { this.entityDAO = entityDAO; } public List<Entity> findEntityByName (String name){ return entityDAO.findByName(name); } }
hoteagleMemberI think I finally get the reason and the solution.
Reason: As for the many-to-one relation, hibernate will default assume that the “one” side is the primary key. However, in my case, it is a unique key on one side table.
solution: There is the solution in Hibernate 3 official document! In the xml for “many” side table (here is the Entity.hbm.xml) add
property-ref="etype"
into the <many-toone …> description line. The full part of that modification is listed below as:
<many-to-one class="hibernate.Codeentitytype" fetch="select" name="codeentitytype" property-ref="etype"> <column name="Type"/> </many-to-one>
That works well. Wondering whether MyEclipse can do this automatically? You know it is not so hard to detect the one side is whether a Unique Key or a Primary Key during reverse engineering.
Or is there some automatic way to let hibernate reverse engineering tool to add this property?
support-swapnaModeratorhoteagle,
Apologies for the delayed response. Thank you for posting the solution.
I have filed a PR for the dev team to check on the feasibility about adding it to the reverse engineering process.
hoteagleMemberso is there some update for this feature? By the way, is there a way to force generating hibernate mapping files without considering any foreign key constraints. That will also be helpful.
thanks.
-
AuthorPosts