-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: detached entity passed to persist
PostPosted: Mon Sep 05, 2011 10:19 pm 
Newbie

Joined: Sat Aug 20, 2011 10:00 pm
Posts: 4
I have 3 entities user, patient and doctor. Every doctor or patient is a user. I don't use inheritance strategy because I couldn't get an answer from my question here: https://forum.hibernate.org/viewtopic.php?f=1&t=1012327

Now I'm trying to achieve a similar point without inheritance. Schema is like that:
User <--- OneToOne --> Doctor
User <--- OneToOne --> Patient
Patient <--- ManyToMany --> Doctor

My entities:
User.java:
Code:
@Entity
@Table(name = "user")
public class User implements Serializable
{
   private static final long serialVersionUID = 1L;
   @Id
   @GeneratedValue
   private int userId;

   @Column(nullable = false, length = 25)
   private String password;

   @Column(nullable = false, columnDefinition = "int(11) unsigned")
   private int type;

   @Column(nullable = false, unique = true, length = 25)
   private String username;

   // bi-directional one-to-one association to Doctor
   @OneToOne(mappedBy = "user", cascade = { CascadeType.ALL })
   private Doctor doctor;

   // bi-directional one-to-one association to Patient
   @OneToOne(mappedBy = "user", cascade = { CascadeType.ALL })
   private Patient patient;

   public User()
   {
   }

   public User(String username, String password)
   {
      this.password = password;
      this.username = username;
   }
   //getters setters
   //...


Patient.java:
Code:
@Entity
@Table(name = "patient")
public class Patient implements Serializable
{
   private static final long serialVersionUID = 1L;

   @Id
   @GeneratedValue(generator = "foreign")
   @GenericGenerator(name = "foreign", strategy = "foreign", parameters = { @Parameter(name = "property", value = "user") })
   private int patientId;

   private String address;

   @Temporal(TemporalType.DATE)
   private Date birthDate;

   @Column(nullable = false)
   private String name;

   private String phone;

   @Column(nullable = false)
   private int sex;

   @Column(nullable = false)
   private String surname;

   // bi-directional many-to-many association to Doctor
   @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE })
   @JoinTable(name = "doctorpatient", joinColumns = { @JoinColumn(name = "patientId") }, inverseJoinColumns = { @JoinColumn(name = "doctorId") })
   private List<Doctor> doctors;

   // bi-directional one-to-one association to User
   @OneToOne(optional = false, cascade = { CascadeType.ALL })
   @JoinColumn(name = "patientId", nullable = false)
   private User user;

   // bi-directional many-to-one association to Record
   @OneToMany(mappedBy = "patient")
   private List<Record> records;

   public Patient()
   {
   }

   public Patient(String name, String surname, int sex, User user)
   {
      this.name = name;
      this.surname = surname;
      this.sex = sex;
      user.setType(User.PATIENT);
      this.user = user;
      this.user.setPatient(this);
   }
   //I've tried to obtain bi-directionality
   public void addDoctor(Doctor doctor)
   {
      if (doctors == null)
         doctors = new ArrayList<Doctor>();
      doctors.add(doctor);
      if (doctor.getPatients() == null)
         doctor.setPatients(new ArrayList<Patient>());
      doctor.getPatients().add(this);
   }
   //getters setters
   //...


Doctor.java:
Code:
@Entity
@Table(name = "doctor")
public class Doctor implements Serializable
{
   private static final long serialVersionUID = 1L;

   @Id
   @GeneratedValue(generator = "foreign")
   @GenericGenerator(name = "foreign", strategy = "foreign", parameters = { @Parameter(name = "property", value = "user") })
   private Integer doctorId;

   private String address;

   @Temporal(TemporalType.DATE)
   private Date birthDate;

   @Column(nullable = false)
   private String name;

   private String phone;

   @Column(nullable = false, unique = true)
   private String regNo;

   @Column(nullable = false)
   private int sex;

   @Column(nullable = false)
   private String surname;

   // bi-directional one-to-one association to User
   @OneToOne(optional = false, cascade = { CascadeType.ALL })
   @JoinColumn(name = "doctorId", nullable = false)
   private User user;

   // bi-directional many-to-many association to Patient
   @ManyToMany(mappedBy = "doctors", cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE })
   private List<Patient> patients;

   public Doctor()
   {
   }

   public Doctor(String name, String surname, String regNo, int sex, User user)
   {
      this.name = name;
      this.regNo = regNo;
      this.sex = sex;
      this.surname = surname;
      user.setType(User.DOCTOR);
      this.user = user;
      this.user.setDoctor(this);
   }
   //I've tried to obtain bi-directionality
   public void addPatient(Patient patient)
   {
      if (patients == null)
         patients = new ArrayList<Patient>();
      patients.add(patient);
      if (patient.getDoctors() == null)
         patient.setDoctors(new ArrayList<Doctor>());
      patient.getDoctors().add(this);
   }
   //getters setters
   //...


I've written junit tests for these entities. The doctor methods are working but patients' not.
This one creates 3 users(2 for patients 1 for doctor), 2 patients and a doctor.
DoctorTest.java:
Code:
@Test
   public void testCreateDoctor()
   {
      for (int i = 0; i < unitNumber; i++)
      {
         boolean result = false;
         User patientUser1 = new User("username" + (i + unitNumber), "password" + (i + unitNumber));
         Patient patient1 = new Patient("name" + i, "surname" + i, i % 2, patientUser1);
         User patientUser2 = new User("username" + (i + 2 * unitNumber), "password" + (i + 2 * unitNumber));
         Patient patient2 = new Patient("name" + i, "surname" + i, i % 2, patientUser2);
         User doctorUser = new User("username" + i, "password" + i);
         Doctor doctor = new Doctor("name" + i, "surname" + i, "regNo" + i, i % 2, doctorUser);
         doctor.addPatient(patient2);
         doctor.addPatient(patient1);
         result = doctorService.createDoctor(doctor);
         assertTrue(result);
      }
   }


But that one doesn't work as I expect:

PatientTest.java:
Code:
@BeforeClass
   public static void setUpBeforeClass() throws Exception
   {
      EntityManagerFactory emf = PersistenceManager.getInstance().getEntityManagerFactory();
      patientService = new PatientServiceImpl(emf);
      unitNumber = 20;
      users = new User[4 * unitNumber];
      doctors = new Doctor[unitNumber];
      for (int i = 3 * unitNumber; i < 4 * unitNumber; i++)
      {
         User doctorUser = new User("username" + i, "password" + i);
         Doctor doctor = new Doctor("name" + i, "surname" + i, "regNo" + i, i % 2, doctorUser);
         doctors[i - 3 * unitNumber] = doctor;
      }
   }

@Test
   public void testCreatePatient()
   {
      for (int i = 0; i < 3 * unitNumber; i++)
      {
         boolean result = false;
         User patientUser = new User("username" + i, "password" + i);
         Patient patient = new Patient("name" + i, "surname" + i, i % 2, patientUser);
         patient.addDoctor(doctors[i % unitNumber]);
         result = patientService.createPatient(patient);
         assertTrue(result);
      }
   }


The for loop inside testCreatePatient executes up to unitNumber. When i becomes unitNumber + 1 (I mean 21), I'm getting detached entity passed to persist: tr.com.stigma.db.entity.User. It creates 20 doctors, 20 patients and 40 users until i gets to 20. At the 21st insert, I try to add a new patient to an existing doctor, consequently to an existing user. How can I do this?

Stack trace is here:

Code:
javax.persistence.RollbackException: Error while committing the transaction
   at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:93)
   at tr.com.stigma.db.service.PatientServiceImpl.createPatient(PatientServiceImpl.java:37)
   at tr.com.stigma.db.service.test.PatientServiceTest.testCreatePatient(PatientServiceTest.java:61)
   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.InvokeMethod.evaluate(InvokeMethod.java:20)
   at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
   at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
   at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
   at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
   at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
   at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
   at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
   at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
   at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
   at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
   at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
   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.PersistentObjectException: detached entity passed to persist: tr.com.stigma.db.entity.User
   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)
   ... 26 more
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: tr.com.stigma.db.entity.User
   at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:127)
   at org.hibernate.impl.SessionImpl.firePersistOnFlush(SessionImpl.java:834)
   at org.hibernate.impl.SessionImpl.persistOnFlush(SessionImpl.java:826)
   at org.hibernate.engine.CascadingAction$9.cascade(CascadingAction.java:357)
   at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
   at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
   at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
   at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
   at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:450)
   at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:282)
   at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
   at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:143)
   at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69)
   at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179)
   at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
   at org.hibernate.impl.SessionImpl.firePersistOnFlush(SessionImpl.java:834)
   at org.hibernate.impl.SessionImpl.persistOnFlush(SessionImpl.java:826)
   at org.hibernate.engine.CascadingAction$9.cascade(CascadingAction.java:357)
   at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
   at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
   at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
   at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:425)
   at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:362)
   at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:338)
   at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
   at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
   at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:475)
   at org.hibernate.event.def.DefaultPersistEventListener.entityIsPersistent(DefaultPersistEventListener.java:159)
   at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132)
   at org.hibernate.impl.SessionImpl.firePersistOnFlush(SessionImpl.java:834)
   at org.hibernate.impl.SessionImpl.persistOnFlush(SessionImpl.java:826)
   at org.hibernate.engine.CascadingAction$9.cascade(CascadingAction.java:357)
   at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
   at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
   at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
   at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
   at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:154)
   at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:145)
   at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88)
   at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
   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)
   ... 26 more


Top
 Profile  
 
 Post subject: Re: detached entity passed to persist
PostPosted: Tue Sep 06, 2011 4:57 pm 
Newbie

Joined: Sat Aug 20, 2011 10:00 pm
Posts: 4
Although nobody replied, I solved it.
I changed @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE }) to @ManyToMany(cascade = { CascadeType.ALL })


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.