JPA:尝试从双向ManyToMany关系中删除实体

时间:2019-04-02 12:47:36

标签: hibernate jpa many-to-many lazy-loading bidirectional-relation

我尝试从ManyToMany-Relation中删除一个实体,但是在通过我的存储库保存了父实体之后,没有任何反应。

UserRepository:

public interface UserRepository extends EntityGraphJpaRepository<User, Long> {

    User findByEmailIgnoreCase(String email);

    Page<User> findBy(Pageable pageable);

    User findByEmail(String name, com.cosium.spring.data.jpa.entity.graph.domain.EntityGraph entityGraph);
}

AbstractEntity

@MappedSuperclass
public abstract class AbstractEntity implements Serializable {

    private static final long serialVersionUID = -2523912452050488728L;

    @Id
    @GeneratedValue
    private Long id;

    @Version
    private int version;

    public Long getId() {
        return id;
    }

    public int getVersion() {
        return version;
    }

    @Override
    public int hashCode() {
        if (id == null) {
            return super.hashCode();
        }

        return 31 + id.hashCode();
    }

    @Override
    public boolean equals(Object other) {
        if (id == null) {
            // New entities are only equal if the instance if the same
            return super.equals(other);
        }

        if (this == other) {
            return true;
        }
        if (!(other instanceof AbstractEntity)) {
            return false;
        }

        boolean test = id.equals(((AbstractEntity) other).id);
        return id.equals(((AbstractEntity) other).id);
    }

}

用户实体

@NamedEntityGraphs(value = {
        @NamedEntityGraph(name = "User.roles.groups", attributeNodes = {
            @NamedAttributeNode("roles"),
            @NamedAttributeNode("groups")
        })
    })
@Entity(name="userInfo")
public class User extends AbstractEntity {

    @ManyToMany(mappedBy = "users", fetch = FetchType.LAZY, cascade= {CascadeType.PERSIST, CascadeType.MERGE}) //inverse side
    private Set<Role> roles = new HashSet<Role>();

    public void addRole(Role role) {
        this.roles.add(role);
        role.getUsers().add(this);
    }

    public void removeRole(Role role) { 
        this.roles.remove(role);
        role.getUsers().remove(this);
    }
//...
}

RoleEntity:

public class Role extends AbstractEntity {
    @ManyToMany(fetch = FetchType.LAZY, cascade= {CascadeType.PERSIST,CascadeType.MERGE}) //owning side
    @JoinTable(
      name = "role_user", 
      joinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"), 
      inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"))
    private Set<User> users = new HashSet<User>(); 

UserService:

@Service
public class UserService implements CrudEntityServiceInterface{

    private UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

public void save(User user) {
        this.userRepository.saveAndFlush(user);
    }


    public User updateRolesForUser(User user,Set<Role> roleItems,RoleService roleService) {

        Set<Role> rolesToRemove = new HashSet<Role>();

        for(Role oldRole: user.getRoles()) {
            //remove roles which are deselected
            if(!roleItems.contains(oldRole)) {
                Optional<Role> oldRoleLoaded = (roleService.getRepository()).findById(oldRole.getId(),EntityGraphs.named("Role.users.groups"));
                rolesToRemove.add(oldRoleLoaded.get()); 
            }
        }

        rolesToRemove.forEach(x -> user.removeRole(x));

        //added selected roles
        roleItems.forEach(x ->  {
            Optional<Role> xLoaded = (roleService.getRepository()).findById(x.getId(),EntityGraphs.named("Role.users.groups"));
            user.addRole(xLoaded.get());
        } );

        return user;


    }
//...
}

在我的控制器中,我称呼类似

user = userService.updateRolesForUser(user,roles,roleService);
userService.save(user);

由于我不想使用Fetch.Eager,因此必须使用entityGraph。

您有什么线索为什么我不能从用户中删除角色?我还尝试了Cascade.Remove-但这不能解决问题,这是不好的做法。

编辑:当我致电

rolesToRemove.forEach(x -> {user.removeRole(x); roleService.save(x);}); 

我要从该关系中删除的实体已删除。但是我认为通过CascadeType.Persist在userRepository上调用save可以更新用户的所有内容?为什么我还要另外呼叫保存角色?

1 个答案:

答案 0 :(得分:0)

旧问题,但角色控制ManyToMany关系。如果您希望对关系保持更改,那么必须更新角色对象,而不是用户端。