views:

127

answers:

2

Hey folks,

I've got a really weird problem with a bi-directional relationship in jpa (hibernate implementation). A User is based in one Region, and a Region can contain many Users.

So...relationship is as follows:

Region object:

@OneToMany(mappedBy = "region", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public Set<User> getUsers() {
  return users;
}
public void setUsers(Set<User> users) {
  this.users = users;
}

User object:

@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER)
@JoinColumn(name = "region_fk")
public Region getRegion() {
  return region;
}
public void setRegion(Region region) {
  this.region = region;
}

So, the relationship as you can see above is Lazy on the region side, ie, I don't want the region to eager load all the users. Therefore, I have the following code within my DAO layer to add a user to an existing user to an existing region object...

public User setRegionForUser(String username, Long regionId){
  Region r = (Region) this.get(Region.class, regionId);
  User u = (User) this.get(User.class, username);
  u.setRegion(r);
  Set<User> users = r.getUsers();
  users.add(u);
  System.out.println("The number of users in the set is: "+users.size());
  r.setUsers(users);
  this.update(r);
  return (User)this.update(u);
}

The problem is, when I run a little unit test to add 5 users to my region object, I see that the region.getUsers() set always stays stuck at 1 object...somehow the set isn't getting added to.

My unit test code is as follows:

public void setUp(){
  System.out.println("calling setup method");
  Region r = (Region)ManagerFactory.getCountryAndRegionManager().get(Region.class, Long.valueOf("2"));
  for(int i = 0; i<loop; i++){
    User u = new User();
    u.setUsername("username_"+i);
    ManagerFactory.getUserManager().update(u);
    ManagerFactory.getUserManager().setRegionForUser("username_"+i, Long.valueOf("2"));
  }
}

public void tearDown(){
  System.out.println("calling teardown method");
  for(int i = 0; i<loop; i++){
    ManagerFactory.getUserManager().deleteUser("username_"+i);
  }
}

public void testGetUsersForRegion(){
  Set<User> totalUsers = ManagerFactory.getCountryAndRegionManager().getUsersInRegion(Long.valueOf("2"));
  System.out.println("Expecting 5, got: "+totalUsers.size());
  this.assertEquals(5, totalUsers.size());
}

So the test keeps failing saying there is only 1 user instead of the expected 5. Any ideas what I'm doing wrong?

thanks very much, Brian

A: 

What is the implementation for update(r)? Are you remembering to commit?

lucas
At the moment, update does the following:<code> public Object update(Object o) { Object a = this.entityManager.merge(o); this.entityManager.flush(); return a; }</code>
Brian
throw a entityManager.getTransaction().commit(); in there at the end and you should be set.
lucas
Whoops, I didn't see your flush() in there. hmm. I don't usually use flush but it seems like it should work.
lucas
Yeah, spring is managing my transactions and I think they're setup fine. The flush should be enough i would have thought
Brian
What are the primary keys/id fields when the users are created? Are they being autogenerated by your db? Can you verify in the loop that they are different?
lucas
yep, verified. They're not auto generated. I'm changing them in the loop and am sure they're different. Thanks for your help though Lucas.
Brian
A: 

What is the implementation of hashcode and equald in User? Maybe all your users are considered the same in the Set so only one gets saved.

Manuel Darveau