USERS表ROLE_ID字段赋值为NULL问题排查求助
USERS表ROLE_ID字段始终为NULL的排查与解决
问题概况
定义了UserEntity和RoleEntity实体类,期望USERS表引用ROLES表的ROLE_ID字段,但创建用户后该字段值始终为NULL。
实体类代码
UserEntity
package com.br.BookStoreAPI.models.entities; import com.br.BookStoreAPI.models.DTOs.loginDTOs.LoginRequestDTO; import jakarta.validation.constraints.*; import jakarta.persistence.*; import lombok.*; import org.springframework.security.crypto.password.PasswordEncoder; import java.time.LocalDateTime; import java.util.Set; @Entity @NoArgsConstructor @Getter @Setter @Table(name = "USERS") public class UserEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "USER_ID") private Long userId; @NotBlank @Column(name = "USER_FIRST_NAME") private String userFirstName; @NotBlank @Column(name = "USER_LAST_NAME") private String userLastName; @NotBlank @Column(name = "USER_EMAIL") private String userEmail; @NotBlank @Column(name = "USER_PASSWORD") private String userPassword; @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "ROLE_ID") private RoleEntity role; @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) @JoinTable( name = "USER_ROLES", joinColumns = @JoinColumn(name = "USER_ID"), inverseJoinColumns = @JoinColumn(name = "ROLE_ID") ) private Set<RoleEntity> roles; @Column(name = "CREATION_DATE") private LocalDateTime creationDate; @Column(name = "MODIFICATION_DATE") private LocalDateTime modificationDate; @PrePersist protected void onCreate() { creationDate = LocalDateTime.now(); } @PreUpdate protected void onUpdate() { modificationDate = LocalDateTime.now(); } public boolean isLoginCorrect(LoginRequestDTO loginRequestDTO, PasswordEncoder passwordEncoder) { return passwordEncoder.matches(loginRequestDTO.password(), this.userPassword); } }
RoleEntity
package com.br.BookStoreAPI.models.entities; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; @Entity @Table(name = "ROLES") @Getter @Setter public class RoleEntity { @Id @Column(name = "ROLE_ID") private Long roleId; @Enumerated(EnumType.STRING) @Column(name = "ROLE", nullable = false) private RoleType role; public enum RoleType { ADMIN(1L), USER(2L); private final long roleId; RoleType(long roleId) { this.roleId = roleId; } public long getRoleId() { return roleId; } } }
创建用户请求体
{ "userFirstName": "MatheusTeste2", "userLastName": "Castilho", "userEmail": "Matheus.castilho124@gmail.com", "userPassword": "senhaSegura" }
UserService创建用户代码
public UserResponseDTO create(UserRequestDTO dto) { var role = roleRepository.findByRoleName(RoleEntity.RoleType.USER.name()); var userFromDb = userRepository.findByUserEmail(dto.userEmail()); if (userFromDb.isPresent()) { throw new UserAlreadyExistsException("User's email " + dto.userEmail() + " is already in use. "); } UserEntity userEntity = new UserEntity(); userEntity.setUserFirstName(dto.userFirstName()); userEntity.setUserLastName(dto.userLastName()); userEntity.setUserEmail(dto.userEmail()); userEntity.setUserPassword(bCryptPasswordEncoder.encode(dto.userPassword())); userEntity.setRoles(Set.of(role)); UserEntity result = userRepository.save(userEntity); return new UserResponseDTO(result); }
问题原因
- 字段未赋值:USERS表的
ROLE_ID字段对应UserEntity中@ManyToOne注解的role属性,但Service创建用户时仅给多对多的roles集合赋值,未给role字段设置值,导致插入时该字段为NULL。 - 实体关系冲突:
UserEntity同时定义了单角色(@ManyToOne)和多角色(@ManyToMany)两种关系,逻辑上存在冲突,需二选一。
解决方案
方案1:使用单角色模式(保留USERS表ROLE_ID字段)
- 修改UserService代码,添加
role字段赋值:
// 在设置roles的代码后添加此行 userEntity.setRole(role);
- (可选)删除
UserEntity中多对多相关代码(roles集合、@JoinTable注解),避免逻辑混淆。
方案2:使用多角色模式(删除USERS表ROLE_ID字段)
- 删除
UserEntity中单角色相关代码:
// 删除这段代码 @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "ROLE_ID") private RoleEntity role;
- 同步删除USERS表的
ROLE_ID列,多角色关系由中间表USER_ROLES维护,现有创建用户逻辑无需修改,roles集合赋值会自动向中间表插入关联数据。
额外检查
确保roleRepository.findByRoleName能查询到数据库中已存在的角色记录,若数据库未预先插入ADMIN/USER角色,需先初始化这些数据,否则关联会失效。
内容的提问来源于stack exchange,提问作者Matheus Castilho
相关产品推荐
相关产品推荐

