39

I have the following entities:

TEAM

@Entity
@Table
public class Team {
[..]
private Set<UserTeamRole> userTeamRoles;

/**
 * @return the userTeamRoles
 */
@OneToMany(cascade = { CascadeType.ALL }, mappedBy = "team", fetch = FetchType.LAZY)
public Set<UserTeamRole> getUserTeamRoles() {
    return userTeamRoles;
}

/**
 * @param userTeamRoles
 *            the userTeamRoles to set
 */
public void setUserTeamRoles(Set<UserTeamRole> userTeamRoles) {
    this.userTeamRoles = userTeamRoles;
}

}

and

USER_TEAM_ROLE

@Entity
@Table(name = "user_team_role")
public class UserTeamRole {

 @ManyToOne(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
 @JoinColumn(name = "FK_TeamId")
 public Team getTeam() {
    return team;
 }
}

Now, when updating a Team entity that contains for example Team.userTeamRoles = {UTR1, UTR2} with {UTR1, UTR3}, I want UTR2 to be deleted. But the way I do it now, the old list remains the same and it only adds UTR3 to the list.

This is how I do it at the moment:

 if (!usersDualListData.getTarget().isEmpty()) {
        // the role for each user within the team will be "employee"
        team.setUserTeamRoles(new HashSet<UserTeamRole>());
        Role roleForUser = roleService
                .getRoleByName(RoleNames.ROLE_EMPLOYEE.name());
        for (User user : usersDualListData.getTarget()) {
            UserTeamRole utr = new UserTeamRole();
            utr.setUser(user);
            utr.setTeam(team);
            utr.setRole(roleForUser);
            team.getUserTeamRoles().add(utr);
        }
    }

teamService.updateTeam(team);

I thought that by doing team.setUserTeamRoles(new HashSet<UserTeamRole>()); the list would be reset and because of the cascades the previous list would be deleted.

Any help is appreciated. Thank you

AndaP
  • 1,308
  • 8
  • 23
  • 40
  • I think is the same problem here: http://stackoverflow.com/questions/2011519/jpa-onetomany-not-deleting-child check it out! – Diogo Moreira Feb 04 '13 at 12:20

1 Answers1

112
  1. Instead of replacing the collection (team.setUserTeamRoles(new HashSet<UserTeamRole>());) you have to clear() the existing one. This happens because if Hibernate loads the entity (and its collections) from DB, it "manages" them, ie. tracks their changes. Generally when using Hibernate it's better not to create any setters for collections (lists, sets). Create only the getter, and clear the collection returned by it, ie:

    team.getUserTeamRoles().clear();

  2. Another thing is that you miss orphan deletion (ie. delete child object when it's removed from collection in the parent). To enable it, you need to add @OneToMany(orphanRemoval=true) in owning entity.

Adam Dyga
  • 8,666
  • 4
  • 27
  • 35
  • @Adam Dyga Hibernate noob here, could you explain more on why it's better not to create any setters for collections? – Jonathan Oct 17 '13 at 23:43
  • @Jonny try to replace a collection in an entity with an new one (eg. new ArrayList()) and see what happens on save ;) – Adam Dyga Oct 18 '13 at 10:45
  • Thanks for clear answer. But can I do same trick if I recreated parent object using `new` keyword and manually inserted ID to it (i.e. object is not "managed" by Hibernate and it in Transient state)? – WelcomeTo Nov 18 '13 at 19:33
  • @MyTitle why would you like to do something like that? – Adam Dyga Nov 19 '13 at 10:13
  • please, check my question http://stackoverflow.com/questions/20057678/hibernate-remove-on-update-child-list?noredirect=1#comment29893886_20057678 – WelcomeTo Nov 19 '13 at 10:22
  • @MyTitle I don't fully understand what you mean by "recreating the parent". But if it's a new entity (transient), it's not managed by Hibernate, so you may overwrite the child collection. – Adam Dyga Nov 19 '13 at 11:02
  • if someone it's so kind to take a look at my question, i would be very happy, because i can't build correct equals / hashCode methods for a many-to-many relationship. thank you http://stackoverflow.com/questions/24737145/equals-and-hashcode-of-these-entities-spring-mvc-hibernate – WoutVanAertTheBest Jul 14 '14 at 17:09