-->
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: @IdClass cause identifier of an instance altered in em.find
PostPosted: Thu Sep 10, 2009 6:37 pm 
Newbie

Joined: Thu Sep 10, 2009 6:21 pm
Posts: 4
Location: Almaty
This is probably a bug!
When i am trying to find my already persisted Entity (Membership with Composite Id ( @IdClass ))
after when my transaction commited it cause

Code:
4:00:20,593 WARN  [arjLoggerI18N] [com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_2] TwoPhaseCoordinator.beforeCompletion - failed for com.arjuna.ats.internal.jta.resources.arjunacore.SynchronizationImple@1f5e42b
javax.persistence.PersistenceException: org.hibernate.HibernateException: identifier of an instance of kz.bee.wx.security.Membership was altered from kz.bee.wx.security.MembershipPk@1a532c to kz.bee.wx.security.MembershipPk@8a7ac2b
   at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:629)



i assume what after calling method em.find() it associates my MembershipPk with found Entity and at sync state it replaces with new MembershipPk.

Here is my sample code

Code:
User u=new User("myuser");
Role r=new Role("myrole");
Group g=new Group("mygroup");
            
Membership m = new Membership();
m.setUser(u);
m.setRole(r);
m.setGroup(g);
            
MembershipPk mk = new MembershipPk();
mk.setUser(u);
mk.setRole(r);
mk.setGroup(g);

System.out.println(em.find(m.getClass(), mk));



and my entity is
Code:
package kz.bee.wx.security;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;

@Entity
@Table(name = "WX_MEMBERSHIP")
@IdClass(MembershipPk.class)
public class Membership {

   private User user;
   private Role role;
   private Group group;
   private boolean enabled;
   
   @Id
   @ManyToOne
   @JoinColumn(name = "USER_NAME_")
   public User getUser() {
      return user;
   }

   public void setUser(User user) {
      this.user = user;
   }

   @Id
   @ManyToOne
   @JoinColumn(name = "ROLE_NAME_")
   public Role getRole() {
      return role;
   }

   public void setRole(Role role) {
      this.role = role;
   }

   @Id
   @ManyToOne
   @JoinColumn(name = "GROUP_NAME_")
   public Group getGroup() {
      return group;
   }

   public void setGroup(Group group) {
      this.group = group;
   }

   @Column(name = "ENABLED_")
   public boolean isEnabled() {
      return enabled;
   }

   public void setEnabled(boolean enabled) {
      this.enabled = enabled;
   }

   @Transient
   public boolean isActive() {
      return this.isEnabled() && this.getRole().isEnabled() && this.getGroup().isEnabled();
   }
   
   @Override
   public String toString() {
      return user+":"+role+":"+group;
   }
   
   @Override
    public boolean equals(Object arg0) {
        if (arg0 == this) {
            return true;
        }
        else if (arg0 instanceof Membership) {
            return user.getName().equals(((Membership)arg0).user.getName()) &&
            role.getName().equals(((Membership)arg0).role.getName()) &&
            group.getName().equals(((Membership)arg0).group.getName());
        }
        return false;
    }

   @Override
    public int hashCode() {
        return user.hashCode() ^ role.hashCode() ^ group.hashCode();
    }
}


and primary key

Code:
package kz.bee.wx.security;

import java.io.Serializable;

import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

@Embeddable
public class MembershipPk implements Serializable {

   /**
    *
    */
   private static final long serialVersionUID = 1L;
   
   private User user;
   private Role role;
   private Group group;
   

   @ManyToOne
   @JoinColumn(name = "USER_NAME_")
   public User getUser() {
      return user;
   }

   public void setUser(User user) {
      this.user = user;
   }

   @ManyToOne
   @JoinColumn(name = "ROLE_NAME_")
   public Role getRole() {
      return role;
   }

   public void setRole(Role role) {
      this.role = role;
   }

   @ManyToOne
   @JoinColumn(name = "GROUP_NAME_")
   public Group getGroup() {
      return group;
   }

   public void setGroup(Group group) {
      this.group = group;
   }
   
   @Override
    public boolean equals(Object arg0) {
        if (arg0 == this) {
            return true;
        }
        else if (arg0 instanceof MembershipPk) {
            return user.getName().equals(((MembershipPk)arg0).user.getName()) &&
            role.getName().equals(((MembershipPk)arg0).role.getName()) &&
            group.getName().equals(((MembershipPk)arg0).group.getName());
        }
        return false;
    }

    @Override
    public int hashCode() {
       return user.hashCode() ^ role.hashCode() ^ group.hashCode();
    }
}


p.s User, Role and Group are simple classes with name as @Id


Top
 Profile  
 
 Post subject: Re: @IdClass cause identifier of an instance altered in em.find
PostPosted: Thu Sep 17, 2009 5:10 pm 
Newbie

Joined: Thu Sep 17, 2009 5:03 pm
Posts: 4
Location: Goiânia/Goiás/Brasil
I have exactly the same error in my application.

How do you solve this? Has anyone any idea about solving this issue?

Thanks in advance!

_________________
Diego Miranda


Last edited by dmarcosm on Tue Sep 22, 2009 2:28 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: @IdClass cause identifier of an instance altered in em.find
PostPosted: Thu Sep 17, 2009 5:26 pm 
Newbie

Joined: Thu Sep 10, 2009 6:21 pm
Posts: 4
Location: Almaty
hi! while i didn't get reply from hibernate guys,
i wrote own EntityIdentifier, it uses em.createQuery instead of em.find

maybe it looks ugly :(, but it works!

code smth like this,
Code:
String criteria = "FROM " + getClazz().getName() + " WHERE ";

            for (String field : identifierFields) {
               criteria += field + "=:" + field + " AND ";
            }

            criteria = criteria.substring(0, criteria.length() - 4);
            
            Query query = entityManager.createQuery(criteria);

            for (String field : identifierFields) {
               Method getter = Reflections.getGetterMethod(identifierIdClass, field);
               Object value = Reflections.invoke(getter, identifier);
               query.setParameter(field, value);
            }

            return query.getSingleResult();


i hope hibernate guys look into this problem in near future :)


Top
 Profile  
 
 Post subject: Re: @IdClass cause identifier of an instance altered in em.find
PostPosted: Thu Sep 17, 2009 5:35 pm 
Newbie

Joined: Thu Sep 17, 2009 5:03 pm
Posts: 4
Location: Goiânia/Goiás/Brasil
Thank for your reply. I'll test your "workaround". =]

I hope it too. It's too weird that hibernate do not support this.

Another solutions would be welcome.

Thanks.

_________________
Diego Miranda


Top
 Profile  
 
 Post subject: Re: @IdClass cause identifier of an instance altered in em.find
PostPosted: Fri Sep 18, 2009 1:23 am 
Newbie

Joined: Fri Sep 18, 2009 12:43 am
Posts: 1
The two "equal" MembershipPk's have different hashCodes (hex-number behind @ symbol) as shown in your stack trace:
Quote:
kz.bee.wx.security.MembershipPk@1a532c to kz.bee.wx.security.MembershipPk@8a7ac2b

so I suspect that MembershipPk.hashCode() is not implemented correctly :)
Perhaps it should be something like this:
Code:
   @Override
    public int hashCode() {
       return user.getName().hashCode() ^ role.getName().hashCode() ^ group.getName().hashCode();
    }

Any other ideas?


Top
 Profile  
 
 Post subject: Re: @IdClass cause identifier of an instance altered in em.find
PostPosted: Fri Sep 18, 2009 4:16 am 
Newbie

Joined: Thu Sep 10, 2009 6:21 pm
Posts: 4
Location: Almaty
it doesnt matter, i've tried it!
hibernate generates forcely new instance,
i spend whole day trying to solve it :(


Top
 Profile  
 
 Post subject: Re: @IdClass cause identifier of an instance altered in em.find
PostPosted: Fri Sep 18, 2009 4:03 pm 
Newbie

Joined: Thu Sep 17, 2009 5:03 pm
Posts: 4
Location: Goiânia/Goiás/Brasil
I've tried implementing both hashCode and equals methods, but it doesn't work.

Code:
identifier of an instance of Test was altered from TestPK@1 to TestPK@1


Even with the same hashCode the error persist.

_________________
Diego Miranda


Top
 Profile  
 
 Post subject: Re: @IdClass cause identifier of an instance altered in em.find
PostPosted: Fri Sep 18, 2009 5:07 pm 
Newbie

Joined: Thu Sep 17, 2009 5:03 pm
Posts: 4
Location: Goiânia/Goiás/Brasil
I've got the solution! (Maybe =])

In my case, I had to implement the "equals" method into the associated class. That is, if you have an A class that is associated with a B class that has a composite id, you must implement the "equals" method in the A class, and it works.

I hope it help someone.

See ya.

_________________
Diego Miranda


Top
 Profile  
 
 Post subject: Re: @IdClass cause identifier of an instance altered in em.find
PostPosted: Mon Aug 09, 2010 5:08 pm 
Newbie

Joined: Mon Aug 09, 2010 4:56 pm
Posts: 4
It worked for me by implementing the hashCode() & equals() method.

Thank you all for supporting. I spent whole lot of time figuring out myself, finally I am glad found the solution here.

Thanks again.


Top
 Profile  
 
 Post subject: Re: @IdClass cause identifier of an instance altered in em.find
PostPosted: Wed Aug 11, 2010 9:14 am 
Newbie

Joined: Mon Aug 09, 2010 4:56 pm
Posts: 4
I am again running into the same problem. I thought it worked and posted the reply on to this thread. Here is the scenario:

I am creating a web application where author performs add/modify/delete on books. (Struts2 - Hibernate)
Example: Author - Books
1. When author goes on edit mode, he can see all of his books under children. When author adds some books and deletes one book and then save works perfectly fine.
2. If he does the same steps again for 2nd time from the same web page, I am getting the below error.

Exception in saveOrUpdateObject()... org.hibernate.HibernateException: identifier of an instance of Book was altered from 37 to 119.

Does any one has ideas?

Thanks,


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.