My question
I have defined a component in my mapping. The component is made up two other components, one not nullable and the other nullable. Of the not nullable component, it is made up of two properties, one a column in my table, the other a derived column that is not persisted.
During my testing, I write tests to make sure persisting an object with one of the not nullable set to a null value throws a DataAccesException with a cause of PropertyValueException. This is intended to highlight to me if the mapping changes without the proper follow-up.
If I leave my derived property in the component mapping, I do not get the DataAccessException. If I remove it I do get the exception thrown.
Ther not-null="true" directive should be making Hibernate tell me there is a problem before a write to the database. Is there some interaction between the elements of the component that is causing this?
Hibernate version:
3.0
Mapping documents:
This mapping does not throw a DataAccessException when I expect it to
<component name="budget" class="com.ilign.ppm.common.ForeignCurrency" >
<component name="baseMoney" class="com.ilign.ppm.common.Money" >
<property name="amount" column="BUDGET" type="big_decimal" not-null="true"/>
<property name="currencyCode" update="false" insert="false" not-null="true" formula="( Select ac.config_value from application_config ac where ac.config_id = '17' )" />
</component>
<component name="srcMoney" class="com.ilign.ppm.common.Money" >
<property name="amount" column="SRC_BUDGET" type="big_decimal" />
<property name="currencyCode" column="SRC_BUDGET_CURRENCY_CODE" type="string" />
</component>
</component>
This mapping does throw the DataAccessException
<component name="budget" class="com.ilign.ppm.common.ForeignCurrency" >
<component name="baseMoney" class="com.ilign.ppm.common.Money" >
<property name="amount" column="BUDGET" type="big_decimal" not-null="true"/>
<component name="srcMoney" class="com.ilign.ppm.common.Money" >
<property name="amount" column="SRC_BUDGET" type="big_decimal" />
<property name="currencyCode" column="SRC_BUDGET_CURRENCY_CODE" type="string" />
</component>
</component>
Code between sessionFactory.openSession() and session.close():
public void testBudgetNotNullable()
{
FinancialYear fy = financialYearDao.load( fy2005_2006 );
String name = "Standards";
DateTime startDate = new DateMidnight( 2005, 1, 1 ).toDateTime();
DateTime endDate = new DateTime( 2005, 12, 31, 23, 59, 59, 999 );
Money baseMoney = null;
Money srcMoney = null;
ForeignCurrency budget = new ForeignCurrency( baseMoney, srcMoney );
OutputClass standards = new OutputClass();
standards.setName( name );
standards.setDescription( name );
standards.setStartDate( startDate );
standards.setEndDate( endDate );
standards.setFinancialYear( fy );
try
{
standards = outputClassDao.create( standards );
fail( "Should have reported budget as not nullable" );
}
catch ( DataAccessException e )
{
assertTrue( e.getCause() instanceof PropertyValueException );
}
catch ( Exception e )
{
fail( e.getMessage() );
}
}
Full stack trace of any exception that occurs:
I get this if I invoke flushSession to force Hibernate to write to the database. This is not good to me as it comes as a GenericJDBCException and could be anything.
org.hibernate.exception.GenericJDBCException: could not insert: [com.ilign.ppm.domain.OutputClass]
at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:82)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:70)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.entity.BasicEntityPersister.insert(BasicEntityPersister.java:1869)
at org.hibernate.persister.entity.BasicEntityPersister.insert(BasicEntityPersister.java:2200)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:46)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:239)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:223)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:136)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:274)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:730)
at com.ilign.ppm.common.SpringDaoTestCase.flushSession(SpringDaoTestCase.java:53)
at com.ilign.ppm.dao.OutputClassDaoHibernateTest.testBudgetNotNullable(OutputClassDaoHibernateTest.java:238)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at junit.textui.TestRunner.doRun(TestRunner.java:116)
at com.intellij.rt.execution.junit2.IdeaJUnitAgent.doRun(IdeaJUnitAgent.java:57)
at junit.textui.TestRunner.start(TestRunner.java:172)
at com.intellij.rt.execution.junit.TextTestRunner2.startRunnerWithArgs(TextTestRunner2.java:23)
at com.intellij.rt.execution.junit2.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:97)
at com.intellij.rt.execution.junit2.JUnitStarter.main(JUnitStarter.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:78)
Caused by: org.firebirdsql.jdbc.FBSQLException: GDS Exception. 335544347. validation error for column BUDGET, value "*** null ***"
at org.firebirdsql.jdbc.AbstractPreparedStatement.internalExecute(AbstractPreparedStatement.java:453)
at org.firebirdsql.jdbc.AbstractPreparedStatement.executeUpdate(AbstractPreparedStatement.java:147)
at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:22)
at org.hibernate.persister.entity.BasicEntityPersister.insert(BasicEntityPersister.java:1853)
... 33 more
Name and version of the database you are using:
Firebird 1.5.2
The generated SQL (show_sql=true):
2005-07-06 11:40:47,319 DEBUG [org.hibernate.SQL] select financialy0_.FINANCIAL_YEAR_ID as FINANCIAL1_0_, financialy0_.VSN as VSN8_0_, financialy0_.NAME as NAME8_0_, financialy0_.START_DATE as START4_8_0_, financialy0_.END_DATE as END5_8_0_ from FINANCIAL_YEAR financialy0_ where financialy0_.FINANCIAL_YEAR_ID=?
2005-07-06 11:40:47,381 DEBUG [org.hibernate.type.LongType] binding '4002' to parameter: 1
2005-07-06 11:40:47,381 DEBUG [org.hibernate.type.IntegerType] returning '5' as column: VSN8_0_
2005-07-06 11:40:47,381 DEBUG [org.hibernate.type.StringType] returning 'FY 05/06' as column: NAME8_0_
2005-07-06 11:40:47,381 DEBUG [org.hibernate.type.TimestampType] returning '2005-04-01 00:00:00' as column: START4_8_0_
2005-07-06 11:40:47,381 DEBUG [org.hibernate.type.TimestampType] returning '2006-03-31 23:59:59' as column: END5_8_0_
2005-07-06 11:40:47,381 DEBUG [org.springframework.transaction.support.TransactionSynchronizationManager] Retrieved value [org.springframework.orm.hibernate3.SessionHolder@1b9a538] for key [org.hibernate.impl.SessionFactoryImpl@27538] bound to thread [main]
2005-07-06 11:41:02,397 DEBUG [org.springframework.jdbc.support.SQLErrorCodesFactory] Looking up default SQLErrorCodes for DataSource [org.springframework.jdbc.datasource.DriverManagerDataSource@b30913]
2005-07-06 11:41:02,397 DEBUG [org.springframework.jdbc.support.SQLErrorCodesFactory] Database product name found in cache for DataSource [org.springframework.jdbc.datasource.DriverManagerDataSource@b30913]: name is 'Firebird'
2005-07-06 11:41:02,397 DEBUG [org.springframework.jdbc.support.SQLErrorCodesFactory] SQL error codes for 'Firebird' not found
2005-07-06 11:41:02,397 DEBUG [org.springframework.transaction.support.TransactionSynchronizationManager] Retrieved value [org.springframework.orm.hibernate3.SessionHolder@1b9a538] for key [org.hibernate.impl.SessionFactoryImpl@27538] bound to thread [main]
2005-07-06 11:41:02,397 DEBUG [org.springframework.transaction.support.TransactionSynchronizationManager] Retrieved value [org.springframework.orm.hibernate3.SessionHolder@1b9a538] for key [org.hibernate.impl.SessionFactoryImpl@27538] bound to thread [main]
2005-07-06 11:43:23,053 DEBUG [org.springframework.jdbc.datasource.DriverManagerDataSource] Creating new JDBC connection to [jdbc:firebirdsql://localhost:3050/d:/FirebirdDBs/ilign.fdb]
2005-07-06 11:43:23,100 DEBUG [org.hibernate.SQL] select next_value from OBJECT_ID with lock
2005-07-06 11:43:23,100 DEBUG [org.hibernate.SQL] update OBJECT_ID set next_value = ? where next_value = ?
2005-07-06 11:43:23,194 DEBUG [com.ilign.ppm.common.audit.AuditLogInterceptor] <FIELD><NAME>vsn</NAME><VALUE>null</VALUE></FIELD><FIELD><NAME>name</NAME><VALUE>Standards</VALUE></FIELD><FIELD><NAME>startDate</NAME><VALUE>2005-01-01T00:00:00.000+13:00</VALUE></FIELD><FIELD><NAME>endDate</NAME><VALUE>2005-12-31T23:59:59.999+13:00</VALUE></FIELD><FIELD><NAME>description</NAME><VALUE>Standards</VALUE></FIELD><FIELD><NAME>contribution</NAME><VALUE>null</VALUE></FIELD><FIELD><NAME>budget</NAME><VALUE>null</VALUE></FIELD><FIELD><NAME>parent</NAME><VALUE>null</VALUE></FIELD><FIELD><NAME>financialYear</NAME><VALUE>4002</VALUE></FIELD>
2005-07-06 11:43:26,085 DEBUG [org.springframework.transaction.support.TransactionSynchronizationManager] Retrieved value [org.springframework.orm.hibernate3.SessionHolder@1b9a538] for key [org.hibernate.impl.SessionFactoryImpl@27538] bound to thread [main]
2005-07-06 11:43:26,100 DEBUG [org.springframework.orm.hibernate3.HibernateTransactionManager] Triggering beforeCompletion synchronization
2005-07-06 11:43:26,100 DEBUG [org.springframework.orm.hibernate3.HibernateTransactionManager] Initiating transaction rollback
2005-07-06 11:43:26,100 DEBUG [org.springframework.orm.hibernate3.HibernateTransactionManager] Rolling back Hibernate transaction on session [org.hibernate.impl.SessionImpl@1289e48]
2005-07-06 11:43:26,116 DEBUG [org.springframework.orm.hibernate3.HibernateTransactionManager] Triggering afterCompletion synchronization
2005-07-06 11:43:26,116 DEBUG [org.springframework.transaction.support.TransactionSynchronizationManager] Clearing transaction synchronization
2005-07-06 11:43:26,116 DEBUG [org.springframework.transaction.support.TransactionSynchronizationManager] Removed value [org.springframework.orm.hibernate3.SessionHolder@1b9a538] for key [org.hibernate.impl.SessionFactoryImpl@27538] from thread [main]
2005-07-06 11:43:26,116 DEBUG [org.springframework.transaction.support.TransactionSynchronizationManager] Removed value [org.springframework.jdbc.datasource.ConnectionHolder@1a517bd] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@b30913] from thread [main]
2005-07-06 11:43:26,116 DEBUG [org.springframework.orm.hibernate3.HibernateTransactionManager] Closing Hibernate session [org.hibernate.impl.SessionImpl@1289e48] after transaction
2005-07-06 11:43:26,116 DEBUG [org.springframework.orm.hibernate3.SessionFactoryUtils] Closing Hibernate Session
2005-07-06 11:43:26,131 INFO [com.ilign.ppm.dao.OutputClassDaoHibernateTest] Rolled back transaction after test execution
Debug level Hibernate log excerpt:
|