我在持久层中遇到了多对多关联的问题。我的场景如下:
一个用户可以拥有多个角色,一个角色可以附加多个用户。在测试过程中我遇到了一个奇怪的行为。我创建了角色对象和几个用户对象。该角色已设置给每个用户。此后,使用 DAO 保存用户。然后,在保存用户对象之前,加载其中一个用户以检查他是否获得了传递给他的角色。呼唤getRoles()
用户上显示角色设置正确。
为了检查反向是否也有效,使用角色 DAO 从数据库加载角色对象。但打电话getUsers()
角色对象上只返回一个空集,尽管它应该包含具有此角色的所有用户。
我仔细检查了数据库表,但一切似乎都正常。用户、角色和 user_role 表均已正确填写。
那么为什么角色对象不包含任何用户呢?
我将 Hibernate 和 Spring 与以下类一起使用。
用户等级
@Entity
@Table
public class User extends BusinessObject {
...
// Option 1
@ManyToMany(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
targetEntity=Role.class)
@JoinTable(name= "user_role",
joinColumns = {@JoinColumn(name="user_id")},
inverseJoinColumns = {@JoinColumn(name="role_id")})
// Option 2
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name= "user_role",
joinColumns = {@JoinColumn(name="user_id")},
inverseJoinColumns = {@JoinColumn(name="role_id")})
private Set<Role> roles = new HashSet<Role>();
...
}
角色类别
@Entity
@Table
public class Role extends BusinessObject {
...
// Option 1
@ManyToMany(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
mappedBy= "roles",
targetEntity = User.class)
// Option 2
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name= "user_role",
joinColumns = {@JoinColumn(name="role_id")},
inverseJoinColumns = {@JoinColumn(name="user_id")})
private Set<User> users = new HashSet<User>();
...
}
为了进行测试,我在 JUnit 测试类中使用以下代码。
@Test
public void test(){
Transaction trans = sessionFactory.getCurrentSession().beginTransaction();
Role userAdminRole = new Role();
userAdminRole.setName(RoleName.USER_ADMIN);
Role userRole = new Role();
userRole.setName(RoleName.USER);
User user1 = new User();
user1.setEmail("[email protected]");
user1.getRoles().add(userAdminRole);
user1.getRoles().add(userRole);
userDao.save(user1);
User user2 = new User();
user2.setEmail("[email protected]");
user2.getRoles().add(role);
userDao.save(user2);
User user3 = new User();
user3.setEmail("[email protected]");
user3.getRoles().add(role);
userDao.save(user3);
trans.commit();
User loadedUser = userDao.load(user1.getId());
// Tests passes
Assert.assertNotNull(loadedUser);
Assert.assertEquals(user1, loadedUser);
Set<Role> roles = loadedUser.getRoles();
// Tests passes
Assert.assertEquals(2, roles.size());
Role loadedUserAdminRole = roleDao.findByName(RoleName.USER_ADMIN);
Set<User> users = loadedUserAdminRole.getUsers();
// Test fails: Count is 0 instead of 3 !!!!!!!
Assert.assertEquals(3, users.size());
}
UPDATE
抱歉我忘了提一件事。当我测试代码时,我当然没有在每个类文件中标记多对多关联两次。相反,我在每个类文件中使用选项 1 或选项 2。