Search code examples
javahibernatemany-to-many

Many-to-many relations in Hibernate doesn't return results


I have two beans classes - User and UserGroup:

User:

@Entity
@Table(name = "user")
public class User implements Serializable {
    private static final long serialVersionUID = -7482853955996650586L;

    @Id
    @Column(name = "id")
    @GeneratedValue
    private Integer id;

    @Column(name = "login")
    private String login;

    @ManyToMany
    @JoinTable(name = "user_x_userGroup",
        joinColumns = {
                @JoinColumn(
                        name = "user_id",
                        foreignKey = @ForeignKey(name = "FK_user_x_userGroup_user_id")
                ) },
        inverseJoinColumns = {
                @JoinColumn(
                        name = "userGroup_id",
                        foreignKey = @ForeignKey(name = "FK_user_x_userGroup_userGroup_id")
                ) })
    private List<UserGroup> userGroups;

    public User() {
        this.userGroups = new ArrayList<>();
    }

    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getLogin() {
        return this.login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    public List<UserGroup> getUserGroups() {
        return this.userGroups;
    }

    public void setUserGroups(List<UserGroup> userGroups) {
        this.userGroups = userGroups;
    }
}

UserGroup:

@Entity
@Table(name = "userGroup")
public class UserGroup implements Serializable, Comparable<UserGroup> {
    private static final long serialVersionUID = -5924845694417474352L;

    @Id
    @Column(name = "id")
    @GeneratedValue
    private Integer id;

    @Column(name = "title")
    private String title;

    @ManyToMany(mappedBy = "userGroups")
    private List<User> users;

    public UserGroup() {
        this.users = new ArrayList<>();
    }

    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getTitle() {
        return this.title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public List<User> getUsers() {
        return this.users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }
}

I'm testing if list of user groups has size 1 in UserServiceTest:

public class UserServiceTest {

    @BeforeClass
    public static void prepareDatabase() throws DAOException {
        MockDatabase.insertUsers();
        MockDatabase.insertUserGroups();
    }

    @Test
    public void shouldGetUserGroupSize() throws Exception {
        UserService userService = new UserService();
        User user = userService.find(1);
        boolean condition = user.getUserGroups().size() == 1;
        assertTrue("User groups size is incorrect!", condition);
    }
}

Unfortunately it returns size 0. I can see in console that it inserts data to user and userGroup table.

Mocking data for database:

public static void insertUsers() throws DAOException {
    UserService userService = new UserService();

    User firstUser = new User();
    firstUser.setLogin("first");
    userService.save(firstUser);

    User secondUser = new User();
    secondUser.setLogin("second");
    userService.save(secondUser);
}

public static void insertUserGroups() throws DAOException {
    UserService userService = new UserService();
    UserGroupService userGroupService = new UserGroupService();

    UserGroup firstUserGroup = new UserGroup();
    firstUserGroup.setTitle("Admin");
    List<User> users = new ArrayList<>();
    users.add(userService.find(1));
    firstUserGroup.setUsers(users);
    userGroupService.save(firstUserGroup);

    UserGroup secondUserGroup = new UserGroup();
    secondUserGroup.setTitle("Random");
    userGroupService.save(secondUserGroup);
}

Here is find method:

public User find(Integer id) throws DAOException {
    User result = (User) retrieveObject(User.class, id);
    if (result == null) {
        throw new DAOException("Object can not be found in database");
    }
    return result;
}

protected static Object retrieveObject(Class cls, Integer id) throws DAOException {
    try {
        Session session = Helper.getHibernateSession();
        if (session == null) {
            session = HibernateUtil.getSessionFactory().openSession();
            Object o = session.get(cls, id);
            session.close();
            return o;
        }
        return session.get(cls, id);
    } catch (HibernateException he) {
        throw new DAOException(he);
    }
}

And here save:

public User save(User user) throws DAOException {
    storeObject(user);
    return (User) retrieveObject(User.class, user.getId());
}

protected static void storeObject(Object object) throws DAOException {
    try {
        Session session = Helper.getHibernateSession();
        session.saveOrUpdate(object);
        session.flush();
        session.beginTransaction().commit();
    } catch (HibernateException he) {
        rollback();
        throw new DAOException(he);
    }
}

It looks it saves data to user table and userGroup table but it doesn't save data to user_x_userGroup table. What can cause this problem?


Solution

  • You don't set the UserGroup instance you persist in the entity that is the owner of the relationship.

    In UserGroup you declare :

    @ManyToMany(mappedBy = "userGroups")
    private List<User> users;
    

    That means that the owner side of the bidirectional relation is the User entity.

    In your actual code, the owner side (User) doesn't reference the UserGroup entity you want to persist, so the UserGroup entity will be persisted but it will not associated to the users field you have set in UserGroup.

    So just set it suitably and it should be ok:

    UserGroup firstUserGroup = new UserGroup();
    firstUserGroup.setTitle("Admin");
    List<User> users = new ArrayList<>();
    // change
    User user = userService.find(1);
    List<UserGroup> groups = new ArrayList<>();
    groups.add(firstUserGroup);
    user.setUserGroups(groups);
    // end change
    users.add(user);          
    firstUserGroup.setUsers(users);
    userGroupService.save(firstUserGroup);
    ...