Hello. This post addresses two problems, but the code is so similar that I thought I'd compile them into one postn. Please let me know if I should create a separate post for each.
Both problems address the way Hibernate manages unique foreign key constraints. I have two classes, Left & Right, that share a bidirectional one-to-one relationship. The relationship is enforced in the database using a unique foreign key constraint in the table for Left.
First problem: Is it possible to make Hibernate nullify foreign key columns when the target of the constraint is deleted? Currently if I create a Left & Right, associate & save them, then delete the right side of the relation -- the side that is the target of the FK constraint -- I get a FK constraint error from the database. Is it possible to instruct Hibernate to null the foreign key record that points to the Right before deleting it? See below for code, mapping, and stack trace. The method testDeleteConstrained shows the problem.
Second (more serious) problem: If I create a Left & Right, associate them , then save the Right -- the side mapped to the table that does NOT contain the FK column -- the fk column is not updated. The relationship isn't saved in the database! The fk column, rightFk, remains null after Right is saved. See the method testFkValue in the code below.
Thanks in advance.
-Dave
Hibernate Version: 2.1.1
Database: Microsoft SQL Server 2000
The code:
Code:
package com.northstar.test.example;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.cfg.Configuration;
public class BidirectionalConstraintTest {
private static SessionFactory sessionFactory;
public static void main(String[] args) {
try {
BidirectionalConstraintTest test = new BidirectionalConstraintTest();
test.testFkValue();
test.testDeleteConstrained();
} catch (HibernateException e) { e.printStackTrace(); }
}
public void testDeleteConstrained() throws HibernateException {
BidirectionalConstraintTest bidi = new BidirectionalConstraintTest();
Left left = new Left(); Right right = new Right();
saveOrUpdate(left);
right.setLeft(left);
left.setRight(right);
saveOrUpdate(right);
saveOrUpdate(left);
delete(right); // whammo! fk constraint error.
delete(left);
}
public void testFkValue() throws HibernateException {
BidirectionalConstraintTest bidi = new BidirectionalConstraintTest();
Left left = new Left(); Right right = new Right();
saveOrUpdate(left);
right.setLeft(left);
left.setRight(right);
saveOrUpdate(right); // Hey, rightFk doesn't get updated!
}
public BidirectionalConstraintTest() throws HibernateException {
Configuration cfg = new Configuration().addClass(Left.class);
sessionFactory = cfg.buildSessionFactory();
}
public void delete(Object o) throws HibernateException {
Transaction tx = null;
Session sess = sessionFactory.openSession();
try {
tx = sess.beginTransaction();
sess.delete(o);
tx.commit();
} catch (HibernateException e) {
if (tx != null) { tx.rollback(); throw e; }
} finally { if (sess != null) sess.close(); }
}
public void saveOrUpdate(Object o) throws HibernateException {
Transaction tx = null;
Session sess = sessionFactory.openSession();
try {
tx = sess.beginTransaction();
sess.saveOrUpdate(o);
tx.commit();
} catch (HibernateException e) {
if (tx != null) { tx.rollback(); throw e; }
} finally { if (sess != null) sess.close(); }
}
}
class Left {
private Long sys_dataStoreId;
private Right right;
public Right getRight() { return right; }
public void setRight(Right right) { this.right = right; }
public Long getSys_dataStoreId() { return sys_dataStoreId; }
public void setSys_dataStoreId(Long sys_dataStoreId) {
this.sys_dataStoreId = sys_dataStoreId;
}
}
class Right {
private Left left;
private Long sys_dataStoreId;
public Left getLeft() { return left; }
public void setLeft(Left left) { this.left = left; }
public Long getSys_dataStoreId() { return sys_dataStoreId; }
public void setSys_dataStoreId(Long sys_dataStoreId) {
this.sys_dataStoreId = sys_dataStoreId;
}
}
The Mapping:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="com.northstar.test.example.Left" table="test_Left" lazy="false" >
<id name="sys_dataStoreId" type="long" column="sys_DataStoreId">
<generator class="increment"/>
</id>
<discriminator column="sys_ObjectType" />
<!-- one-to-one relation with the fk in the table for this entity -->
<many-to-one name="right"
class="com.northstar.test.example.Right"
column="rightFk"
unique="true"
cascade="none"
outer-join="false"
/>
</class>
<class name="com.northstar.test.example.Right" table="test_Right" lazy="false" >
<id name="sys_dataStoreId" type="long" column="sys_DataStoreId">
<generator class="increment"/>
</id>
<discriminator column="sys_ObjectType" />
<!-- bidirectional one-to-one relation with fk in the table for the opposite entity -->
<one-to-one name="left"
class="com.northstar.test.example.Left"
property-ref="right"
constrained="true"
cascade="none"
outer-join="false"
/>
</class>
</hibernate-mapping>
Exception:
Code:
Hibernate: insert into test_Right (sys_ObjectType, sys_DataStoreId) values ('com
.northstar.test.example.Right', ?)
Hibernate: update test_Left set rightFk=? where sys_DataStoreId=?
Hibernate: delete from test_Right where sys_DataStoreId=?
- SQL Error: 547, SQLState: 23000
- [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]DELETE statement conflic
ted with COLUMN REFERENCE constraint 'LeftToRight'. The conflict occurred in dat
abase 'wms_weblogic', table 'test_Left', column 'rightFk'.
- SQL Error: 3621, SQLState: HY000
- [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]The statement has been t
erminated.
- could not delete: [com.northstar.test.example.Right#2]
java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]DEL
ETE statement conflicted with COLUMN REFERENCE constraint 'LeftToRight'. The con
flict occurred in database 'wms_weblogic', table 'test_Left', column 'rightFk'.
at com.microsoft.jdbc.base.BaseExceptions.createException(Unknown Source)
at com.microsoft.jdbc.base.BaseExceptions.getException(Unknown Source)
at com.microsoft.jdbc.sqlserver.tds.TDSRequest.processErrorToken(Unknown Source
)
at com.microsoft.jdbc.sqlserver.tds.TDSRequest.processReplyToken(Unknown Source
)
at com.microsoft.jdbc.sqlserver.tds.TDSRPCRequest.processReplyToken(Unknown Sou
rce)
at com.microsoft.jdbc.sqlserver.tds.TDSRequest.processReply(Unknown Source)
at com.microsoft.jdbc.sqlserver.SQLServerImplStatement.getNextResultType(Unknow
n Source)
at com.microsoft.jdbc.base.BaseStatement.commonTransitionToState(Unknown Source
)
at com.microsoft.jdbc.base.BaseStatement.postImplExecute(Unknown Source)
at com.microsoft.jdbc.base.BasePreparedStatement.postImplExecute(Unknown Source
)
at com.microsoft.jdbc.base.BaseStatement.commonExecute(Unknown Source)
at com.microsoft.jdbc.base.BaseStatement.executeUpdateInternal(Unknown Source)
at com.microsoft.jdbc.base.BasePreparedStatement.executeUpdate(Unknown Source)
at net.sf.hibernate.impl.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:
22)
at net.sf.hibernate.persister.EntityPersister.delete(EntityPersister.java:582)
at net.sf.hibernate.impl.ScheduledDeletion.execute(ScheduledDeletion.java:29)
at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2308)
at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2266)
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2187)
at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:61)
at com.northstar.test.example.BidirectionalConstraintTest.delete(BidirectionalC
onstraintTest.java:52)
at com.northstar.test.example.BidirectionalConstraintTest.testDeleteConstrained
(BidirectionalConstraintTest.java:28)
at com.northstar.test.example.BidirectionalConstraintTest.main(BidirectionalCon
straintTest.java:16)
- Could not synchronize database state with session
net.sf.hibernate.JDBCException: could not delete: [com.northstar.test.example.Ri
ght#2]
at net.sf.hibernate.persister.EntityPersister.delete(EntityPersister.java:601)
at net.sf.hibernate.impl.ScheduledDeletion.execute(ScheduledDeletion.java:29)
at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2308)
at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2266)
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2187)
at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:61)
at com.northstar.test.example.BidirectionalConstraintTest.delete(BidirectionalC
onstraintTest.java:52)
at com.northstar.test.example.BidirectionalConstraintTest.testDeleteConstrained
(BidirectionalConstraintTest.java:28)
at com.northstar.test.example.BidirectionalConstraintTest.main(BidirectionalCon
straintTest.java:16)
Caused by: java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC][SQ
LServer]DELETE statement conflicted with COLUMN REFERENCE constraint 'LeftToRigh
t'. The conflict occurred in database 'wms_weblogic', table 'test_Left', column
'rightFk'.
at com.microsoft.jdbc.base.BaseExceptions.createException(Unknown Source)
at com.microsoft.jdbc.base.BaseExceptions.getException(Unknown Source)
at com.microsoft.jdbc.sqlserver.tds.TDSRequest.processErrorToken(Unknown Source
)
at com.microsoft.jdbc.sqlserver.tds.TDSRequest.processReplyToken(Unknown Source
)
at com.microsoft.jdbc.sqlserver.tds.TDSRPCRequest.processReplyToken(Unknown Sou
rce)
at com.microsoft.jdbc.sqlserver.tds.TDSRequest.processReply(Unknown Source)
at com.microsoft.jdbc.sqlserver.SQLServerImplStatement.getNextResultType(Unknow
n Source)
at com.microsoft.jdbc.base.BaseStatement.commonTransitionToState(Unknown Source
)
at com.microsoft.jdbc.base.BaseStatement.postImplExecute(Unknown Source)
at com.microsoft.jdbc.base.BasePreparedStatement.postImplExecute(Unknown Source
)
at com.microsoft.jdbc.base.BaseStatement.commonExecute(Unknown Source)
at com.microsoft.jdbc.base.BaseStatement.executeUpdateInternal(Unknown Source)
at com.microsoft.jdbc.base.BasePreparedStatement.executeUpdate(Unknown Source)
at net.sf.hibernate.impl.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:
22)
at net.sf.hibernate.persister.EntityPersister.delete(EntityPersister.java:582)
... 8 more