-->
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.  [ 4 posts ] 
Author Message
 Post subject: Query on Simple ManyToMany returns duplicate objects
PostPosted: Fri Mar 07, 2008 12:00 am 
Regular
Regular

Joined: Wed Dec 21, 2005 6:57 pm
Posts: 70
We are migrating from XDoclet based markup to annotations, and find that queries now return duplicate entries. Our first query is on login, where we retreive the Roles for a user.

The prior XDoclet mappings worked fine, but now the (hibernate criterion) to retrieve a user with specified userID and password returns multiple users (one per role). I appreciate the semantics of the outer-join, but I'm puzzled since the XDoclet approach was able to query properly.

I've left in the XDoclet tags, so you can see that the old mapping used lazy="false" and the new mapping uses fetch=FetchType.EAGER. Is this incorrect?




Hibernate version:
core 3.2.5, annotations 3.3.0

Mapping documents:
Code:

@Entity
@Table(name="user")
@Proxy(lazy=false)
public class User {

/**
     *            @hibernate.set
     *             name="roles"
     *             table="user_has_role"
     *                lazy="false"
     *                cascade="save-update"
     *            @hibernate.collection-key
     *                column="user_guid"
     *            @hibernate.collection-many-to-many
     *                class="com.app.Role"
     *             column="role_guid"
     */
    @ManyToMany(fetch=FetchType.EAGER, targetEntity=com.app.Role.class)
    @Cascade({CascadeType.SAVE_UPDATE})
    @JoinTable(name="user_has_role",
    joinColumns={@JoinColumn(name="user_guid")},
    inverseJoinColumns={@JoinColumn(name="role_guid")})
    public Set getRoles() {...


@Entity
@Table(name="role")
@Proxy(lazy=false)
public class Role {
    @Basic
    @Column(name="Role", nullable=false)
    public String getName() {
        return this.name;
    }
...



The generated SQL (show_sql=true):
Code:
    [exec] 22:45:06,765 INFO  [STDOUT] Hibernate:
select this_.user_guid as user1_65_1_, this_.isActive as isActive65_1_, this_.Password as Password65_1_, this_.UserID as UserID65_1_,
roles2_.user_guid as user1_3_, role3_.role_guid as role2_3_, role3_.role_guid as role1_57_0_
from
   user this_
   left outer join user_has_role roles2_ on this_.user_guid=roles2_.user_guid
   left outer join role role3_ on roles2_.role_guid=role3_.role_guid where (this_.UserID=? and this_.Password=?)


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 10, 2008 4:13 pm 
Newbie

Joined: Mon Mar 10, 2008 3:45 pm
Posts: 2
I'm noticing a very similar issue after I created a reversible OneToOne relationship.

A brief synopsys of my mappings:

Code:
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="type", discriminatorType=DiscriminatorType.STRING)
public abstract class Filter {
   private int id = 0;
   protected Cluster cluster = null;
   private String name = "";
   
   protected Filter(){
   }

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   public int getId() {
      return id;
   }

   protected void setId(int id) {
      this.id = id;
   }
   
   @Column(unique=true, updatable=false)
   public String getName() {
      return name;
   }

   protected void setName(String name) {
      this.name = name;
   }

   @OneToOne(cascade={CascadeType.ALL})
   @JoinColumn(updatable = false, nullable = true)
   public Cluster getCluster() {
      return cluster;
   }

   protected void setCluster(Cluster cluster) {
      this.cluster = cluster;
   }
}


The ManyToMany in question however, is found in a class that extends the above one:
Code:
@Entity
@DiscriminatorValue(value="accessFilter")
public class AccessFilter extends Filter {
   private List<UserRole> userRoles = new ArrayList<UserRole>();
   
   protected AccessFilter(){
   }

   @ManyToMany(targetEntity=UserRole.class, fetch=FetchType.EAGER)
   @JoinTable(name="UserRole_Filter", joinColumns=@JoinColumn(name="filter_id"), inverseJoinColumns=@JoinColumn(name="userRole_id"))
   private List<UserRole> getUserRoles() {
      return userRoles;
   }

   private void setUserRoles(List<UserRole> userRole) {
      this.userRoles = userRole;
   }
}

And the reversed OneToOne from Filter:
Code:
@Entity
public class Cluster{
   private Filter filter = null;
   private int id = 0;

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   public int getId() {
      return id;
   }

   protected void setId(int id) {
      this.id = id;
   }

   @OneToOne(mappedBy="cluster")
   public Filter getFilter(){
      return filter;
   }
   
   private void setFilter(Filter filter){
      this.filter = filter;
   }
}


If I comment out the reverse side of the OneToOne relationship (the reference in class Cluster) between Filter and Cluster, everything in AccessFilter is fine. However, with the reversed side of the OneToOne implemented, I get duplicate values in userRole set of AccessFilter (single values repeated 10's of times).

These duplicate values can not be found in the database, it appears that hibernate is selecting these rows multiple times.

My hibernate versions:
Hibernate Annotations 3.3.0.GA
Hibernate 3.2.5
Hibernate EntityManager 3.3.1.GA
running in Jboss 4.0.5.GA


Top
 Profile  
 
 Post subject: Multiple Bags?
PostPosted: Tue Mar 11, 2008 10:54 pm 
Regular
Regular

Joined: Wed Dec 21, 2005 6:57 pm
Posts: 70
Do you have multiple bags mapped somehow? your List mapped with ManyToMany but no indexColumn is a "bag" in hibernate.

Multiple bags are rejected in our version of hibernate (3.2.0) but maybe not in yours.

Try adding an indexColumn or mapping it to a Set since the order of the userRoles is not being preserved anyway.

Please post here when you figure it out.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 12, 2008 3:24 pm 
Newbie

Joined: Mon Mar 10, 2008 3:45 pm
Posts: 2
I am not sure why having a List without an IndexColumn would result in duplicate entries with hibernate. I would have expected a List where the order is not specified.

That said, changing the type to a Set instead of a List did fix the issue.

I would be interested in knowing why a List without an IndexColumn resulted in this behavior. Particularly why it would behave properly in one case and then apparently break when a seemingly unrelated OneToOne was made bi-directional.

Thanks for your help.


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