I'm using Hibernate 4.0 Final and ojdbc6 to develop my web application. Everything is ok except when I try to insert a new parent/child relationship. First of all, these are the entities:
@Entity
@Table(name = "EMPLOYEE")
public class Employee implements Serializable, Cloneable {
@Id
@SequenceGenerator(name = "seq", sequenceName = "P_SEQ")
@GeneratedValue(generator = "seq")
@Column(name = "ID_EMPLOYEE")
private long idEmployee;
......
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "employee", orphanRemoval = true)
@Fetch(FetchMode.SELECT)
@BatchSize(size = 10)
private Set<Address> addresses;
......
}
@Entity
@Table(name = "ADDRESS")
public class Address implements Serializable, Cloneable, Comparable {
@Id
@SequenceGenerator(name = "seq", sequenceName = "P_SEQ")
@GeneratedValue(generator = "seq")
@Column(name = "ID_ADDRESS")
private long idAddress;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ID_EMPLOYEE")
private Employee employee;
.......
}
Let's see these two scenarios:
This is the transaction handler:
public static void save(Employee employee) throws HibernateException, Exception {
Session session = HibernateUtil.getCurrentSession();
session.beginTransaction();
try {
session.saveOrUpdate(employee);
} catch (Exception ex) {
session.refresh(employee);
HibernateUtil.closeSession();
throw ex;
}
HibernateUtil.commitTransaction();
}
public static void commitTransaction() throws Exception {
Transaction tx = getSessionFactory().getCurrentSession().getTransaction();
try {
if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
tx.commit();
}
} catch (Exception ex) {
tx.rollback();
throw ex;
} finally {
closeSession();
}
}
As you can imagine, the 2.b case is the one I'm concerned about. I've debugged the transaction and this is what I get when I call the save() method (which is in a DAO class):
idEmployee
is properly set (taken from the sequence) and the address is binded to the employee and has a valid idAddress
(taken from the sequence, as well).org.hibernate.exception.ConstraintViolationException
, although both idEmployee
and idAddress
has been previously properly set.In short, the Exception come out just during the commit process. It's like if this began commiting the child (address) instead the parent (employee).
What am I doing wrong? Can anybody help me? Thanks in advance.
UPDATED. Above, you can see the main parts of the two classes involved in the problem. Now, here you are the methods that call them besides the trace of exception. They are in the order they are called.
Belonging to the DataBacking class:
public void save(ActionEvent event) {
try {
EmployeeDAO.save(selectedEmployee);
newEmployee(); //reset the employee and its collections
} catch (ConstraintViolationException ex) {
Utilities.addFacesMessage(FacesMessage.SEVERITY_WARN, ex.getMessage(), "");
} catch (Exception ex) {
Utilities.log("error", ex.getCause().toString());
Utilities.addFacesMessage(FacesMessage.SEVERITY_WARN, ex.getMessage(), "");
}
}
Belonging to the EmployeeDAO class:
public static void save(Employee employee) throws HibernateException, Exception {
Session session = HibernateUtil.getCurrentSession();
session.beginTransaction();
try {
session.saveOrUpdate(employee);
} catch (Exception ex) {
session.refresh(employee);
HibernateUtil.closeSession();
throw ex;
}
HibernateUtil.commitTransaction();
}
Belonging to the HibernateUtil class:
public static void commitTransaction() throws Exception {
Transaction tx = getSessionFactory().getCurrentSession().getTransaction();
try {
if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
tx.commit();
}
} catch (Exception ex) {
tx.rollback();
throw ex;
} finally {
closeSession();
}
}
Right after that the EmployeeDAO.save() method calls to session.SaveOrUpdate(employee), I get the following trace:
2013-03-12 07:22:55,958 [DEBUG, org.hibernate.internal.SessionImpl] Opened session at timestamp: 13630693759
2013-03-12 07:22:57,584 [DEBUG, org.hibernate.engine.transaction.spi.AbstractTransactionImpl] begin
2013-03-12 07:22:57,585 [DEBUG, org.hibernate.engine.jdbc.internal.LogicalConnectionImpl] Obtaining JDBC connection
2013-03-12 07:22:57,586 [DEBUG, org.hibernate.engine.jdbc.internal.LogicalConnectionImpl] Obtained JDBC connection
2013-03-12 07:22:57,587 [DEBUG, org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction] initial autocommit status: true
2013-03-12 07:22:57,587 [DEBUG, org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction] disabling autocommit
2013-03-12 07:23:00,285 [DEBUG, org.hibernate.SQL]
select
P_SEQ.nextval
from
dual
2013-03-12 07:23:00,361 [DEBUG, org.hibernate.id.SequenceGenerator] Sequence identifier generated: BasicHolder[java.lang.Long[5665]]
2013-03-12 07:23:00,365 [DEBUG, org.hibernate.event.internal.AbstractSaveEventListener] Generated identifier: 5665, using strategy: org.hibernate.id.SequenceGenerator
2013-03-12 07:23:00,411 [DEBUG, org.hibernate.SQL]
select
P_SEQ.nextval
from
dual
2013-03-12 07:23:00,417 [DEBUG, org.hibernate.id.SequenceGenerator] Sequence identifier generated: BasicHolder[java.lang.Long[5666]]
2013-03-12 07:23:00,421 [DEBUG, org.hibernate.event.internal.AbstractSaveEventListener] Generated identifier: 5666, using strategy: org.hibernate.id.SequenceGenerator
And after the commit has been invoked:
2013-03-12 07:24:53,288 [DEBUG, org.hibernate.engine.transaction.spi.AbstractTransactionImpl] committing
2013-03-12 07:24:53,336 [DEBUG, org.hibernate.event.internal.AbstractFlushingEventListener] Processing flush-time cascades
2013-03-12 07:24:53,343 [DEBUG, org.hibernate.event.internal.AbstractFlushingEventListener] Dirty checking collections
2013-03-12 07:24:53,403 [DEBUG, org.hibernate.engine.internal.Collections] Collection found: [org.svq.pol.gesper.bean.Employee.addresses#5665], was: [<unreferenced>] (initialized)
2013-03-12 07:24:53,439 [DEBUG, org.hibernate.event.internal.AbstractFlushingEventListener] Flushed: 2 insertions, 0 updates, 0 deletions to 2 objects
2013-03-12 07:24:53,440 [DEBUG, org.hibernate.event.internal.AbstractFlushingEventListener] Flushed: 1 (re)creations, 0 updates, 0 removals to 1 collections
2013-03-12 07:24:53,453 [DEBUG, org.hibernate.internal.util.EntityPrinter] Listing entities:
2013-03-12 07:24:53,454 [DEBUG, org.hibernate.internal.util.EntityPrinter] org.svq.pol.gesper.bean.Address{address=fasdf, pc=, city=fadsf, idAddress=5666, operator=xxxxx, province=, telef2=, movDate=Tue Mar 12 07:21:15 CET 2013, telef1=, employee=org.svq.pol.gesper.bean.Employee#5665, version=0}
2013-03-12 07:24:53,456 [DEBUG, org.hibernate.internal.util.EntityPrinter] org.svq.pol.gesper.bean.Employee{surname=fadsf, user=null, dob=Tue Jan 01 00:00:00 CET 1980, address=[org.svq.pol.gesper.bean.Address#5666], pob=fadsf, operator=xxxxx, movDate=Tue Mar 12 07:21:15 CET 2013, version=0, name=fasdf, gender=H, idEmployee=5665, id=12345678}
2013-03-12 07:24:53,572 [DEBUG, org.hibernate.SQL]
insert
into
EMPLOYEE
(SURNAME, ID, MOV_DATE, DOB, GENDER, POB, OPERATOR, USER, VERSION, ID_EMPLOYEE)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2013-03-12 07:24:53,793 [DEBUG, org.hibernate.SQL]
insert
into
ADDRESS
(pc, address, MOV_DATE, OPERATOR, ID_EMPLOYEE, city, province, telef_1, telef_2, version, ID_ADDRESS)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2013-03-12 07:24:53,943 [DEBUG, org.hibernate.engine.jdbc.spi.SqlExceptionHelper] ORA-02291: integrity constraint (PERPLADM.ADDRESS_EMPLOYEE_FK) violated - parent key not found
[n/a]
java.sql.SQLIntegrityConstraintViolationException: ORA-02291: integrity constraint (PERPLADM.ADDRESS_EMPLOYEE_FK) violated - parent key not found
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:445)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:879)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:450)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:207)
at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1044)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1329)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3584)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3665)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1352)
at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:122)
at org.hibernate.engine.jdbc.internal.proxy.AbstractProxyHandler.invoke(AbstractProxyHandler.java:81)
at $Proxy46.executeUpdate(Unknown Source)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:56)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2849)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3290)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:80)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:273)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:265)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:186)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:323)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1081)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:315)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at org.svq.pol.gesper.utility.HibernateUtil.commitTransaction(HibernateUtil.java:57)
at org.svq.pol.gesper.dao.EmployeeDAO.save(EmployeeDAO.java:110)
at org.svq.pol.gesper.backing.DataBacking.save(DataBacking.java:498)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.apache.el.parser.AstValue.invoke(AstValue.java:262)
at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:278)
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:148)
at javax.faces.event.ActionEvent.processListener(ActionEvent.java:88)
at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:769)
at javax.faces.component.UICommand.broadcast(UICommand.java:300)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:409)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:964)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
2013-03-12 07:24:54,027 [WARN, org.hibernate.engine.jdbc.spi.SqlExceptionHelper] SQL Error: 2291, SQLState: 23000
2013-03-12 07:24:54,027 [ERROR, org.hibernate.engine.jdbc.spi.SqlExceptionHelper] ORA-02291: integrity constraint (PERPLADM.ADDRESS_EMPLOYEE_FK) violated - parent key not found
The Solution In order to remedy this error, you will need to insert the value that you attempted to place in the child table into the parent table first. Once inserted as a parent row, you can go back and insert the value into the child table.
Integrity constraint violations occur when an insert, update, or delete statement violates a primary key, foreign key, check, or unique constraint or a unique index. Attempt to insert duplicate key row in object <object_name> with unique index <index_name> .
Fixed: SQLSTATE[23000]: Integrity constraint violation: 1052 This issue occurs when more than one table are having the same column name and in a join query, the column name is being used without the alias of the table name.
It causes violation only if the tuple in relation 1 is deleted which is referenced by foreign key from other tuples of table 2 in the database, if such deletion takes place then the values in the tuple of the foreign key in table 2 will become empty, which will eventually violate Referential Integrity constraint.
After few days struggling with this, I eventually found what the problem was and, obviously, the solution. As far as I know, the mapping shown above is correct (at least, the application works properly). The only problem was in the database, where there was a trigger for inserting the sequence. This way, everytime I tried to insert an employee (and its address), Hibernate gave me two sequence numbers (one for the parent and another for the child), which were correctly set. However, at the precise moment of doing the commit, Oracle gave me two more sequence numbers, and this time incorrectly set, I mean, the foreign key didn't match the parent's primary key.
But as I need triggers, I have to do one more step: I have to modify these ones so they check whether the :new.ID
value is NULL
or not. If it is, it means that the trigger has been triggered from outside Hibernate (i.e. another application), and therefore I take the nextval from the sequence, otherwise I leave the value that comes from Hibernate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With