I am having a problem performing a delete operation using hibernate and was hoping someone could help me out here.
I am using Hibernate and Spring and have a table in the database based on the following configurations:
Spring-based tranaction manager:
Code:
<bean id="myTxManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
Hibernate definition:
Code:
[b]<hibernate-mapping>
<class name="com.domain.EmployeeUser" table="employee_domain">
<id name="userID" column="user_id" length="15"/>
<many-to-one name="domain" column="domain_id"/>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.domain.Domain" table="domain">
<id name="domain_id" type="string" column="domain_id" length="10"/>
<property name="description" type="string" column="description" not-null="true" length="40"/>
<set name="domainCountries" inverse="true" fetch="subselect" lazy="false" cascade="all, delete-orphan">
<key>
<column name="domain_id" not-null="true" />
</key>
<one-to-many class="com.domain.DomainCountry"/>
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.domain.DomainCountry" table="domain_country">
<composite-id>
<key-many-to-one name="domain" column="domain_id"/>
<key-property name="country" type="string" column="country" length="2"/>
</composite-id>
</class>
</hibernate-mapping>[/b]
Code that takes care of delete action:
Code:
public void delete(EmployeeUser user) {
getHibernateTemplate().delete(user);
}
Code that takes care of add/update action:
Code:
public void delete(EmployeeUser user) {
getHibernateTemplate().saveOrUpdate(user);
}
What basically happens is that users are able to select a domain in user interface and can assign it to themselves. So from a list of valid domain id's users can select one domain, and this domain is assigned to users and stored in the database table "employee_domain". They can also choose to delete the domain id by deselecting the domain for this user. In such case the delete method is called to remove the entry from the table employee_domain.
Following describes the situation I am puzzled with:
1- If user already has a domain assigned to him (there is already an entry in the table employee_domain), removing the domain calls the delete method which results in calling "getHibernateTemplate().delete(user)" and removing the entry form the table. following queries are performed:
Code:
select
employeeus_.user_id,
employeeus_.domain_id as domain2_19_
from
employee_domain employeeus_
where
employeeus_.user_id=?
delete
from
employee_domain
where
user_id=?
Assiging a domain to user calls the "getHibernateTemplate().saveOrUpdate(user)"
Everything is fine, selecting and de-selecting works fines and table is updated properly.
2- If the user has no entry in the table, e.g. this is the first time user is being assigned a domain, selecting a domain calls "getHibernateTemplate().saveOrUpdate(user)". A new entry is added in the table with user id and domain id. If after this action user deselects the domain, e.g. decide to remove the domain for this user, "getHibernateTemplate().delete(user)" is called. But instead of delete being called in hibernate, an update operation is attempted to be executed with the following statements:
Code:
select
employeeus_.user_id,
employeeus_.domain_id as domain2_19_
from
employee_domain employeeus_
where
employeeus_.user_id=?
2008-05-27 15:36:54,491 [WebContainer : 0] DEBUG SQL -
select
domain_.domain_id,
domain_.description as descript2_14_
from
domain domain_
where
domain_.domain_id=?
2008-05-27 15:36:54,507 [WebContainer : 0] DEBUG SQL -
update
employee_domain
set
domain_id=?
where
user_id=?
It seems like instead of delete, hibernate calls update statement trying to update the table entry with a NULL value, and following exception is thrown:
2008-05-27 15:36:54,585 [WebContainer : 0] DEBUG SdcmPortlet - Caught exception during action phase - forwarding to render phase
org.springframework.orm.hibernate3.HibernateJdbcException: JDBC exception on Hibernate data access; nested exception is org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
Caused by:
org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:237)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:142)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:562)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:654)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:624)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:307)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:117)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:210)
at $Proxy83.delete(Unknown Source)
at com.mvc.employeesettings.EmployeeSettingsController.onSubmitAction(EmployeeSettingsController.java:77)
at org.springframework.web.portlet.mvc.SimpleFormController.processFormSubmission(SimpleFormController.java:322)
at org.springframework.web.portlet.mvc.AbstractFormController.handleActionRequestInternal(AbstractFormController.java:389)
at com.mvc.BaseFormController.handleActionRequestInternal(BaseFormController.java:79)
at org.springframework.web.portlet.mvc.AbstractController.handleActionRequest(AbstractController.java:197)
at org.springframework.web.portlet.mvc.SimpleControllerHandlerAdapter.handleAction(SimpleControllerHandlerAdapter.java:46)
at org.springframework.web.portlet.DispatcherPortlet.doActionService(DispatcherPortlet.java:638)
at com.portlet.SdcmPortlet.doActionService(SdcmPortlet.java:62)
........
Caused by:
java.sql.BatchUpdateException: ORA-01407: cannot update ("SDCM"."EMPLOYEE_DOMAIN"."DOMAIN_ID") to NULL
at oracle.jdbc.dbaccess.DBError.throwBatchUpdateException(DBError.java:459)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:4373)
at com.ibm.ws.rsadapter.jdbc.WSJdbcStatement.pmiExecuteBatch(WSJdbcStatement.java:1173
........
Strange thing is that the same code is called in both cases. It seems like hibernate decide to do an update instead of delete even though I am calling the delete method.
Does anyone know how hibernate figures out to call update instead of delete in the second scenario? and how can I make sure delete is called and not update?
Cheers,
devx