Although I'm using javax.persistence.CascadeType.ALL, org.hibernate.annotations.CascadeType.ALL, and OnDeleteAction.CASCADE I couldn't manage to delete parent row.
My code is like that:
Code:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Person
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int personId;
//other fields getters setters
}
@Entity
public class Patient extends Person
{
// bi-directional many-to-one association to Doctor
@ManyToOne(optional = false, targetEntity=Doctor.class)
@JoinColumn(name = "doctorId", nullable = false)
private Doctor doctor;
//getter/setters, no other fields, just doctor
}
@Entity
public class Doctor extends Person
{
// bi-directional many-to-one association to Patient
@OneToMany(mappedBy = "doctor", orphanRemoval = true, cascade = { javax.persistence.CascadeType.ALL })
@Cascade({ CascadeType.ALL })
@ForeignKey(name = "FK_DOCTOR")
@OnDelete(action = OnDeleteAction.CASCADE)
private List<Patient> patients;
//getter/setters, no other fields, just patients
}
public boolean deleteDoctor(Doctor doctor)
{
EntityManager em = null;
EntityTransaction entityTransaction = null;
boolean result = false;
try
{
em = getEntityManagerFactory().createEntityManager();
entityTransaction = em.getTransaction();
entityTransaction.begin();
doctor = em.merge(doctor);
em.remove(doctor);
entityTransaction.commit();
result = true;
}
catch (Exception exception)
{
exception.printStackTrace();
}
em.close();
return result;
}
I have one base class Person and 2 inherited classes Doctor and Patient. One doctor can have one or more patients but a patient is related to only one doctor. That is so simple. But for hours I couldn't delete a doctor that have patients referencing on it. I want the patients to be deleted when their doctor is deleted.
The exception trace is:
Code:
HibernateLog --> 05:20:32 WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 1451, SQLState: 23000
HibernateLog --> 05:20:32 ERROR org.hibernate.util.JDBCExceptionReporter - Cannot delete or update a parent row: a foreign key constraint fails (`mobilhm`.`patient`, CONSTRAINT `FK_DOCTOR` FOREIGN KEY (`doctorId`) REFERENCES `doctor` (`personId`))
javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:93)
at tr.com.stigma.mobilhm.db.controller.service.DoctorServiceImpl.deleteDoctor(DoctorServiceImpl.java:139)
at tr.com.stigma.test.mobilhm.db.controller.PatientServiceImplTest.tearDownAfterClass(PatientServiceImplTest.java:52)
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:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:37)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not delete: [tr.com.stigma.mobilhm.db.entity.Doctor#10]
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1215)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1148)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:81)
... 17 more
Caused by: org.hibernate.exception.ConstraintViolationException: could not delete: [tr.com.stigma.mobilhm.db.entity.Doctor#10]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2728)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2911)
at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:97)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:189)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:76)
... 17 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`mobilhm`.`patient`, CONSTRAINT `FK_DOCTOR` FOREIGN KEY (`doctorId`) REFERENCES `doctor` (`personId`))
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1039)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3597)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3529)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1990)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2151)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2625)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2119)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2415)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2333)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2318)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2710)
... 28 more
What I need to do? I'm using all deletion cascades, orphan removal etc.
Please tell me the problem. It must work, isn't it?
UPDATE:
I've looked at the generated schema:
Code:
HibernateLog --> 16:05:57 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport -
drop table if exists mobilhm.Doctor
HibernateLog --> 16:05:57 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport -
drop table if exists mobilhm.Patient
HibernateLog --> 16:05:57 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport -
drop table if exists mobilhm.Person
HibernateLog --> 16:05:57 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport -
drop table if exists mobilhm.User
HibernateLog --> 16:05:57 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport -
create table mobilhm.Doctor (
personId integer not null,
primary key (personId)
)
HibernateLog --> 16:05:57 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport -
create table mobilhm.Patient (
personId integer not null,
doctorId integer not null,
primary key (personId)
)
HibernateLog --> 16:05:57 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport -
create table mobilhm.Person (
personId integer not null auto_increment,
address varchar(255),
birthDate varchar(255),
height float not null,
name varchar(255) not null,
phone varchar(255),
sex integer not null,
surname varchar(255) not null,
weight float not null,
userId integer not null,
primary key (personId),
unique (userId)
)
HibernateLog --> 16:05:57 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport -
create table mobilhm.User (
userId integer not null auto_increment,
password varchar(32) not null,
username varchar(32) not null unique,
primary key (userId)
)
HibernateLog --> 16:05:57 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport -
alter table mobilhm.Doctor
add index FK7A547D3FAB36233C (personId),
add constraint FK7A547D3FAB36233C
foreign key (personId)
references mobilhm.Person (personId)
HibernateLog --> 16:05:57 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport -
alter table mobilhm.Patient
add index PATIENT_DOCTOR_FK (doctorId),
add constraint PATIENT_DOCTOR_FK
foreign key (doctorId)
references mobilhm.Doctor (personId)
HibernateLog --> 16:05:57 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport -
alter table mobilhm.Patient
add index FK340C82E5AB36233C (personId),
add constraint FK340C82E5AB36233C
foreign key (personId)
references mobilhm.Person (personId)
HibernateLog --> 16:05:57 DEBUG org.hibernate.tool.hbm2ddl.SchemaExport -
alter table mobilhm.Person
add index PERSON_USER_FK (userId),
add constraint PERSON_USER_FK
foreign key (userId)
references mobilhm.User (userId)
with the mapping for these annotation configuration:
Code:
@Entity
public class User
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int userId;
@Column(length = 32, nullable = false, unique = true)
private String username;
@Column(length = 32, nullable = false)
private String password;
@OneToOne(mappedBy = "user")
@Cascade({ CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE })
private Person person;
}
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Person
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int personId;
private int sex;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String surname;
private String phone;
private String address;
private String birthDate;
private float height;
private float weight;
@OneToOne(optional = false)
@JoinColumn(name = "userId")
@Cascade({ CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE })
@ForeignKey(name = "PERSON_USER_FK")
@OnDelete(action = OnDeleteAction.CASCADE)
private User user;
}
@Entity
public class Patient extends Person
{
// bi-directional many-to-one association to Doctor
@ManyToOne(optional=false)
@JoinColumn(name = "doctorId", nullable=false)
@ForeignKey(name = "PATIENT_DOCTOR_FK")
@OnDelete(action = OnDeleteAction.CASCADE)
private Doctor doctor;
}
@Entity
public class Doctor extends Person
{
// bi-directional many-to-one association to Patient
@OneToMany(mappedBy = "doctor", orphanRemoval = true)
@Cascade({ CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE })
private List<Patient> patients;
}
As you see hibernate is aware of foreign keys PERSON_USER_FK and PATIENT_DOCTOR_FK but doesn't generate Cascade statements. I will go mad please help me.