java - Spring + JPA/Hibernate 不保存多对多映射

标签 java spring hibernate jpa

情况

我有一个 RoleEntity 和一个 UserEntityRoleEntity 包含 UserEntity 的列表,反之亦然,从而产生多对多 关系。

我的 UserEntity:

public class UserEntity implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    @Column(unique = true, nullable = false)
    private String username;
    @Column(name = "first_name", nullable = false)
    private String firstName;
    @Column(name = "last_name", nullable = false)
    private String lastName;
    @Column(nullable = false)
    private String email;

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.REFRESH)
    @JoinTable(name = "uas_user_role",
        joinColumns = @JoinColumn(name = "uas_user_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "uas_role_id", referencedColumnName = "id"),
        uniqueConstraints = {
        @UniqueConstraint(columnNames = {"uas_user_id", "uas_role_id"})}
    )
    private Set<RoleEntity> roles = new HashSet<>();
...
}

我的 RoleEntity:

public class RoleEntity implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    @Column(unique = true, nullable = false)
    private String name;

    @ManyToMany(mappedBy = "roles")
    private Set<UserEntity> users;

    @ManyToMany
    @JoinTable(
        name = "uas_role_permission",
        joinColumns
        = @JoinColumn(name = "uas_role_id", referencedColumnName = "id"),
        inverseJoinColumns
        = @JoinColumn(name = "uas_permission_id", referencedColumnName = "id"),
        uniqueConstraints = {
        @UniqueConstraint(columnNames = {"uas_role_id", "uas_permission_id"})}
    )
    private Set<PermissionEntity> permissions;
...
} 

目标

现在我想通过简单地更新单个实体来更改映射。例如,我想将 UserEntity 添加到 id=1 的 RoleEntity:

{
    "id": 1,
    "name": "Admin_Role",
    "users": [{"id": 1}
    ]
}

将此 RoleEntity 保存到它的角色存储库 (JPARepository.saveAndFlush(Serializable)),成功解析隐含的 UserEntity 并返回更新的角色实体

 {
    "id": 1,
    "name": "Admin_Role",
    "users": [{
            "id": 1,
            "username": "admin",
            "firstName": "Administrator",
            "lastName": "Administrator",
            "email": "info@example.com",
        }
    ]
}

问题

我的测试都通过了,因为我只检查了保存命令的返回值。 现在我发现在坚持之后执行 roleRepository.findOne(1) 时,我将收到以下 RoleEntity:

{
    "id": 1,
    "name": "Admin_Role",
    "users": []
}

UserEntity 映射没有持久化。 此外,在设置 spring.jpa.show-sql=true 时,我看到在 saveAndFlush 命令期间仅执行了 SELECT 操作。 我只想使用 创建映射,不想允许编辑映射实体,这就是我禁用任何级联的原因。

我希望通过这种方法创建一个映射。我究竟做错了什么?

解决方案

正如 Amer Qarabsa 提到的: 要创建双向映射,需要在两侧进行设置。在保存实体后添加一行就可以了:

@Transactional
public RoleDto updateRole(RoleDto role) {
    RoleEntity roleEntity = roleRepository.findOne(role.getId());
    if (roleEntity==null){
        throw new ResourceNotFoundException();
    }
    final RoleEntity savedRoleEntity = roleRepository.saveAndFlush(roleEntity);
    savedRoleEntity.getUsers().forEach(user -> user.getRoles().add(savedRoleEntity));
    return savedRoleEntity;
}

使用 .saveAndFlush(roleEntity) 我将首先更新 RoleEntity 并让 JPA 解析 UserEntity。在此之后,我只需将 RoleEntity 设置为角色的每个 UserEntity。在我的例子中,我不需要手动保存,因为事务将负责保存任何未保存的更改。

最佳答案

在双向关系中,做到这一点并不简单,您不能如此简单地获取 json 并将其映射到实体,关系的每一端都应该有对另一端的引用,因此在您的情况下,您需要采用角色实体中的每个用户实体并设置它的角色实体然后保存。

关于java - Spring + JPA/Hibernate 不保存多对多映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47903876/

相关文章:

java - 我的数据在哪里?安卓工作室

java - 带有注释的Bean定义继承?

java - 使用条件选择查询

hibernate - JPA/Hibernate 中的条件/复合 JoinColumn

java - 在 Java 中从边和顶点绘制 map

java - 抽象类及其子类

java - Spring MVC 表单使用 modelAttribute 提交

java - 为什么我使用 Spring Boot/Spring Social 指南示例获得到 Twitter 的空连接?

java - 为什么 hibernate 不在 OneToMany 的所有者端设置外键

java - 如何防止断词无限循环