java - JPA/Hibernate "simple"OneToMany 单向/清除集不起作用

标签 java hibernate jpa one-to-many

我不知道我做错了什么,但显然我无法与 hibernate 创建简单的 OneToMany 关系。

这是我的表格在数据库中的外观: enter image description here 我只会展示相关部分,因此问题不会变得臃肿。 我的用户看起来像

@Entity(name = "CORE_USER")
public class User extends AbstractPersistentObject {

    ...

    @ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
    @JoinTable(name = "CORE_USER_TO_ROLE", 
        joinColumns = { @JoinColumn(name = "USER_ID") }, 
        inverseJoinColumns = { @JoinColumn(name = "ROLE_ID") })
    private Set<UserRole> roles = new HashSet<UserRole>();      

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "USER_ID")
    private Set<UserRoleParam> userRoleParams = new HashSet<UserRoleParam>();

    ...(getter and setters)

}

此处核心用户角色参数实体

@Entity(name = "CORE_USER_ROLE_PARAM")
public class UserRoleParam extends AbstractPersistentObject {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ROLE_ID")
    private UserRole userRole;

    @Column(name = "ROLE_PARAMETER")
    private String paramter;

    ...(getter and setter)....
}

UserRole 实体

@Entity(name="CORE_USER_ROLE")
public class UserRole  extends AbstractPersistentObject {

    @Enumerated(EnumType.STRING)
    @Column(name = "ROLE_NAME", length = 30, nullable=false, unique=true)
    private UserRoleEnum roleName;

    ...(getter and setters)
}

当我在测试中这样做时:

@Test
@Transactional(propagation = Propagation.NEVER)
public void saveUserRoleParametersTest() throws Exception {

    // load an user which exists and check params is zero
    UserDTO userDTO = userService.getUserDTO(Users.DE678_ACTIVE_ALLROLES.getObject().getId());
    Assert.assertNotNull(userDTO);
    Assert.assertNotNull(userDTO.getUserRoleParams());
    Assert.assertEquals(0, userDTO.getUserRoleParams().size());

    Map<UserRoleEnum, List<String>> userRoleParams = new HashMap<>();
    userRoleParams.put(UserRoleEnum.BASIC, new ArrayList<>());
    userRoleParams.get(UserRoleEnum.BASIC).add("BASIC_PARAM");

    // save params to user
    userService.saveUserRoleParameters(Users.DE678_ACTIVE_ALLROLES.getObject().getId(), userRoleParams);


    userDTO = userService.getUserDTO(Users.DE678_ACTIVE_ALLROLES.getObject().getId());
    Assert.assertNotNull(userDTO);
    Assert.assertNotNull(userDTO.getUserRoleParams());
    Assert.assertEquals(1, userDTO.getUserRoleParams().size());
    Assert.assertEquals(1, userDTO.getUserRoleParams().get(UserRoleEnum.BASIC).size());
    Assert.assertTrue(userDTO.getUserRoleParams().get(UserRoleEnum.BASIC).contains("BASIC_PARAM"));

    // delete params of user
    userService.saveUserRoleParameters(Users.DE678_ACTIVE_ALLROLES.getObject().getId(), null);

    userDTO = userService.getUserDTO(Users.DE678_ACTIVE_ALLROLES.getObject().getId());
    Assert.assertNotNull(userDTO);
    Assert.assertNotNull(userDTO.getUserRoleParams());
    Assert.assertEquals(0, userDTO.getUserRoleParams().size());
}

这也是我调用的用户服务方法:

@Override
public void saveUserRoleParameters(final String userId, final Map<UserRoleEnum, List<String>> userRoleParams) throws UserNotFoundException {
    User user = userDAO.get(userId);

    if (user == null) {
        throw new UserNotFoundException(userId);
    }

    if (userRoleParams == null || userRoleParams.isEmpty()) {
        user.getUserRoleParams().clear();
    } else {
        List<UserRole> roles = userDAO.getUserRolesByEnums(userRoleParams.keySet());
        Map<UserRoleEnum, UserRole> enumToEntity = new HashMap<>();
        roles.stream().forEach(r -> enumToEntity.put(r.getRoleName(), r));

        for (Entry<UserRoleEnum, List<String>> entry : userRoleParams.entrySet()) {
            UserRoleParam urp = new UserRoleParam(enumToEntity.get(entry.getKey()), entry.getValue().stream().collect(Collectors.joining(";")));
            user.getUserRoleParams().add(urp);
        }
    }
    userDAO.saveOrUpdate(user);
}

问题是我的测试在第一次调用 saveUserRoleParameters 服务方法时失败,这是(编辑:现在启用了 sql 日志):

DEBUG [main] 12.05.17 08:46:50.264  org.hibernate.engine.jdbc.spi.SqlStatementLogger@logStatement: select user0_.id as id1_0_0_, user0_.version as version2_0_0_, user0_.ACTIVE as ACTIVE1_38_0_, user0_.APP_LANG as APP_LANG2_38_0_, user0_.DEFAULT_MODULE as DEFAULT_3_38_0_, user0_.ORGA_UNIT as ORGA_UNI4_38_0_, user0_.USER_FULL_NAME as USER_FUL5_38_0_, user0_.USER_NAME as USER_NAM6_38_0_ from CORE_USER user0_ where user0_.id=?
DEBUG [main] 12.05.17 08:46:50.270  org.hibernate.engine.jdbc.spi.SqlStatementLogger@logStatement: select userrole0_.id as id1_0_, userrole0_.version as version2_0_, userrole0_.ROLE_NAME as ROLE_NAM1_41_ from CORE_USER_ROLE userrole0_ where userrole0_.ROLE_NAME in (?)
DEBUG [main] 12.05.17 08:46:50.287  org.hibernate.engine.jdbc.spi.SqlStatementLogger@logStatement: select userrolepa0_.USER_ID as USER_ID3_0_0_, userrolepa0_.id as id1_42_0_, userrolepa0_.id as id1_0_1_, userrolepa0_.version as version2_0_1_, userrolepa0_.ROLE_PARAMETER as ROLE_PAR1_42_1_, userrolepa0_.ROLE_ID as ROLE_ID2_42_1_ from CORE_USER_ROLE_ROLE_PARAM userrolepa0_ where userrolepa0_.USER_ID=?
DEBUG [main] 12.05.17 08:46:50.290  org.hibernate.engine.jdbc.spi.SqlStatementLogger@logStatement: insert into CORE_USER_ROLE_PARAM (version, ROLE_PARAMETER, ROLE_ID, id) values (?, ?, ?, ?)
WARN  [main] 12.05.17 08:46:50.291  org.hibernate.engine.jdbc.spi.SqlExceptionHelper@logExceptions: SQL Error: 23502, SQLState: 23502
ERROR [main] 12.05.17 08:46:50.291  org.hibernate.engine.jdbc.spi.SqlExceptionHelper@logExceptions: NULL nicht zulässig für Feld "USER_ID"
NULL not allowed for column "USER_ID"; SQL statement:
insert into CORE_USER_ROLE_ROLE_PARAM (version, ROLE_PARAMETER, ROLE_ID, id) values (?, ?, ?, ?) [23502-175]
WARN  [main] 12.05.17 08:46:50.291  org.hibernate.engine.jdbc.spi.SqlExceptionHelper@logExceptions: SQL Error: 23502, SQLState: 23502
ERROR [main] 12.05.17 08:46:50.292  org.hibernate.engine.jdbc.spi.SqlExceptionHelper@logExceptions: NULL nicht zulässig für Feld "USER_ID"
NULL not allowed for column "USER_ID"; SQL statement:

jpa 不应该将 UserId 放在它所属的地方吗?我想要的是一种单向关系,其中用户知道 UserRoleParams,但反之则不然。就像这里的例子 http://www.objectdb.com/api/java/jpa/annotations/relationship

编辑#2: 我找到了解决方案。我在用户实体上添加了以下内容:

@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "USER_ID", nullable = false)
private Set<UserRoleParam> userRoleParams = new HashSet<UserRoleParam>();

现在我遇到了清除集合不会被持久化的问题。我的测试失败,因为第二次检查 Set 是否为空失败。这表明参数仍然设置。

最佳答案

字段User.userRoleParamsUserRoleParam.user是双向关系的一部分。为此,您必须添加 mappedBy="user"@OneToMany 一侧。

您不能将这两个部分作为独立关系(即单向 1-N 和单向 N-1)重复使用相同的 FK 列(“USER_ID”)。

至于your documentation you linked to in the comments ,单向 1-N 的唯一使用在另一侧没有字段(并且您在关系的另一侧确实有一个字段)。

自此回答以来,用户已更改了他们的问题!我为什么要打扰?

关于java - JPA/Hibernate "simple"OneToMany 单向/清除集不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43930693/

相关文章:

java - JBeret 和 JSR352,关于重启和持久数据的一些说明

hibernate - 您如何在GORM子文档字段中进行不同的查询?

java - Spring Hibernate 事务开销

java - 扩展泛型类时遇到问题

java - 关于在读取调用中使用偏移量的说明

hibernate - 防止 JPA 中多对多关系的联接表中出现重复条目

java - JPA 实体管理器 : merge() is trying to create a new row in the db - why?

hibernate - AnnotationException : A Foreign key refering has the wrong number of column. 应该是 2

java - 跨平台 JAD(Java 反编译器)(或替代方案?)

java - OptimisticLockException 之后重试方法时出错 - org.postgresql.util.PSQLException : This statement has been closed