You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
}

问题原因

  1. 字段未赋值:USERS表的ROLE_ID字段对应UserEntity中@ManyToOne注解的role属性,但Service创建用户时仅给多对多的roles集合赋值,未给role字段设置值,导致插入时该字段为NULL。
  2. 实体关系冲突: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 18:07:02