-->
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.  [ 10 posts ] 
Author Message
 Post subject: OneToMany Relationship does not work
PostPosted: Mon Dec 10, 2007 1:34 pm 
Newbie

Joined: Wed Oct 24, 2007 6:39 am
Posts: 7
Hi,

I'm trying to realize a bidirectional one-to-many relationship but I'm always getting a org.hibernate.NonUniqueObjectException!

I want to have a band with several bandmembers:

Code:
public class Band {

   @OneToMany (cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)//(mappedBy="artist")
   @LazyCollection(LazyCollectionOption.FALSE)
   @JoinColumn (name="memberId")
   @org.hibernate.annotations.IndexColumn(name = "musicianId")
        private List<MusicianData>   members = null;
}

public class BandMember {

        @ManyToOne
   @JoinColumn (name="memberId", nullable=false, insertable=false, updatable=false)
        private Band   band;
}


Then I get a Band from the database and close the session:

Code:
band = (band)session.get("Band", id);


In a new session I add a list of BandMembers and set their associated Band to the band:

Code:
for(int i = 0; i < bandMembers.size(); i++) {
   band.getMembers().add(bandMembers.get(i));
   bandMembers.get(i).setBand(band);
   session.save(bandMembers.get(i));
}
session.flush();


Afterwards I close the session again.
The Bandmembers and the Band should now be persistent, shouldn't they?
In the database I cannot detect any changes, though.

Next I change other attributes of the Band, which should be in detached state after my understanding - there's no session open.

At last, I open again a new session and make an update for the Band:

Code:
session.update(band);


Here I get the following exception:

Code:
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [BandMember#0]


But it would work fine if i made the onetomany-attributes transient.

Any help would be great!!!

thanks, Stefan


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 10, 2007 4:14 pm 
Beginner
Beginner

Joined: Tue Nov 27, 2007 9:44 am
Posts: 46
Hi,

don't expect a solution, but let's try to shed some light on this.

Shouldn't this be a List<BandMember>?
Quote:
private List<MusicianData> members = null;


Next, I'd try to leave out the JoinColumn annotations. The way they are defined now looks wrong to me.

Where are your commits? I haven't seen where you commit the changes you've made. It'd be better if you could post some more code.

Coming to your update problem. You wrote:
Quote:
At last, I open again a new session and make an update for the Band:

session.update(band);


You have a detached object, so you need to merge it to the new session before committing. Like so:
Code:
Transaction tx = session.beginTransaction();
session.merge(band);
tx.commit();


Good Luck,
Frank


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 18, 2007 9:18 am 
Newbie

Joined: Wed Oct 24, 2007 6:39 am
Posts: 7
Thanks for the help so far!

I've changed some things in my code but still it won't work.

I've still the same classes:

Code:
public class Band {

   @OneToMany (cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)//(mappedBy="artist")
   @LazyCollection(LazyCollectionOption.FALSE)
   @JoinColumn (name="memberId")
   @org.hibernate.annotations.IndexColumn(name = "musicianId")
        private List<BandMember>   members = null;
}

public class BandMember {

   @ManyToOne
   @JoinColumn (name="memberId", nullable=false, insertable=false, updatable=false)
        private Band   band;
}


First I get a Band from the database:

Code:
try {
   session = hibernateUtil.openSession();
         
   session.beginTransaction();
         
   band = (Band)session.get("Band", id);
         
   session.getTransaction().commit();
}
catch(HibernateException he) {
   he.printStackTrace();
   return null;
}
finally {
   hibernateUtil.closeSession(session);
}


I still add a list of BandMembers to their associated Band but I do not call session.save() anymore because the mapping to the BandMember-Table in the database should be done by the Band in this configuration:

Code:
for(int i = 0; i < bandMembers.size(); i++) {
   band.getMembers().add(bandMembers.get(i));
   bandMembers.get(i).setBand(band);
}


At this point I use no session at all. It's just working with the Java objects.

Then I want to update my Band, so that both the Band-Table and the BandMember-Table in the database should be updated.

Code:
try {
   session = hibernateUtil.openSession();
   
   session.beginTransaction();
   
   session.merge(memberData);
   session.update(memberData);
      
   session.getTransaction().commit();         
}
catch(HibernateException he) {
   throw new HibernateException(he);
}
finally {
   hibernateUtil.closeSession(session);
}


I've tried to add the merge-Method as proposed but still I get following Exception:

Code:
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [Band#24601]


I don't see how there can already be another object with the same identifier associated to this session, because I just opened the session before making the merge and update calls.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 18, 2007 6:07 pm 
Beginner
Beginner

Joined: Tue Nov 27, 2007 9:44 am
Posts: 46
Where is the code between getting the band from the database and merging memberData (whatever that is)?

Do you have hashCode() and equals() methods defined in your Entity classes?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 19, 2007 4:24 am 
Newbie

Joined: Wed Oct 24, 2007 6:39 am
Posts: 7
The code between getting the band from the database and merging memberData is next to the for-loop just some calls of setter-methods of band. Updating the Band worked already fine before I added the bandMember stuff with its OneToMany relationship.

I have neither hashCode() nor equals() methods defined in the Band class.

I should add that the memberData is of type Band! Sorry, that was not clear from my code - the code from loading and merging/updating the band is from different methods I call.

But all in all I'm just loading the Band from the database, calling the for-loop, calling some setter methods and trying to merge/update the band. Nothing else happens in between.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 19, 2007 5:01 am 
Beginner
Beginner

Joined: Tue Nov 27, 2007 9:44 am
Posts: 46
Then I suggest you start by creating the hashCode() and equals() methods for your Entity classes, they are vital for Persistence.

Make sure you take the identifiying field(s) into account when creating the methods. If you use Eclipse, hashCode and equals can easily be created by right-clicking in your class' source and selecting Source -> Generate hashCode() and equals() then chose the identifiying fields.

If that does not help, please post your complete code between getting the entity from the DB to merging it back.

Regards,
Frank


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 19, 2007 8:13 am 
Newbie

Joined: Wed Oct 24, 2007 6:39 am
Posts: 7
Ok, here is the complete code between getting and merging the entity:

Code:
band = memberUtil.getBandById(band.getId());

if(band == null)
   return false;
      
BandMember musician1 = new BandMember();
BandMember musician2 = new BandMember();

musician1.setName(memberName);
musician1.setFunction(function);
musician1.setDescription(description);

musician2.setName(memberName);
musician2.setFunction(function);
musician2.setDescription(description);

List<BandMember> bandMembers = new ArrayList<BandMember>();      
bandMembers.add(musician1);
bandMembers.add(musician2);

for(int i = 0; i < bandMembers.size(); i++) {
   band.getMembers().add(bandMembers.get(i));
   bandMembers.get(i).setBand(band);
}

User liferayUser = band.getLiferayUser();
Contact liferayContact = band.getLiferayContact();
      
if(artistname != null && artistname.compareTo("") != 0)
   band.setNickName(artistname);
else {
   AccountSettingsError.handleMissingInput(aRequest, aResponse, false, true);
   return false;
}

if(numMembers != null)
   band.setNumMembers(Integer.parseInt(numMembers));
else {
   AccountSettingsError.handleMissingInput(aRequest, aResponse, false, true);
   return false;
}

if(birthdate != null && birthmonth != null && birthyear != null) {
   
   if(isDateValid(Integer.parseInt(birthdate), Integer.parseInt(birthmonth), Integer.parseInt(birthyear))) {
   
      Calendar cal = Calendar.getInstance();
      cal.set(Integer.parseInt(birthyear), Integer.parseInt(birthmonth), Integer.parseInt(birthdate));                     
      liferayContact.setBirthday(cal.getTime());
   }
   else {
      AccountSettingsError.handleInvalidDate(aRequest, aResponse, false, true);
      return false;
   }
}

if(messagesPerMail != null) {         
   if(messagesPerMail.compareTo("yes") == 0)
      band.setGetEmailMessages(true);
   else
      band.setGetEmailMessages(false);
}
else
   band.setGetEmailMessages(false);

if(password != null && passwordControl != null) {         
   if(password.compareTo(passwordControl) == 0 && password.compareTo("") != 0) {
      updatePassword(liferayUser, password, passwordControl);
   }
}

if(friendlyURL != null)
   band.setFriendlyURL(friendlyURL);
else
   band.setFriendlyURL("");

band.setLiferayUser(liferayUser);
band.setLiferayContact(liferayContact);

if(!memberUtil.updateMember(band))
   return false;


The variables like password, nickname etc. have valid values. None of the else-branches is executed!

The complete method getBandById is this:

Code:
public Band getBandById(long id) {
      
   Session session = null;
   Band band = null;
   
   try {
      session = hibernateUtil.openSession();
      
      session.beginTransaction();
      
      band = (Band)session.get("Band", id);
      
      session.getTransaction().commit();
   }
   catch(HibernateException he) {
      he.printStackTrace();
      return null;
   }
   finally {
      hibernateUtil.closeSession(session);
   }
   
   return band;
}


And the complete method updateMember is this:

Code:
public synchronized void updateMember(Object memberData)
            throws HibernateException {
      
   Session session = null;
   
   try {
      session = hibernateUtil.openSession();
      
      session.beginTransaction();
      
      session.merge(memberData);
      session.update(memberData);
      
      session.getTransaction().commit();         
   }
   catch(HibernateException he) {
      throw new HibernateException(he);
   }
   finally {
      hibernateUtil.closeSession(session);
   }
}


I've implemented the hashcode() and equals() methods in my entity classes, now, but the exception is just the same.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 20, 2007 7:45 am 
Beginner
Beginner

Joined: Tue Nov 27, 2007 9:44 am
Posts: 46
and how does your BandMember class look like?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 21, 2007 6:06 am 
Pro
Pro

Joined: Tue Jun 12, 2007 4:13 am
Posts: 209
Location: Berlin, Germany
[quote]
session.merge(memberData);
session.update(memberData);
[/quote

Why do you call update after merge? Just merge should do the thing.

Carlo


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 21, 2007 12:57 pm 
Newbie

Joined: Wed Oct 24, 2007 6:39 am
Posts: 7
Thanks for all the help. :)
It was just the update-call that wretched the thing. With merge it works just fine. :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 10 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.