子表在 JPA 中的 OneToMany 关系中没有映射

Posted

技术标签:

【中文标题】子表在 JPA 中的 OneToMany 关系中没有映射【英文标题】:Child table is not mapping in OneToMany relationship in JPA 【发布时间】:2021-06-15 02:58:36 【问题描述】:

我正在尝试在 UserRole 之间建立 一对多 关系。

一个用户可以有多个角色。

这是用户类的代码

@Entity

public class User 
    
    @Id
    private int id;
    private String name;
    private String password;
    private String email;
    private String phoneNo;

    @OneToMany(
                targetEntity = Role.class,
                mappedBy = "user", 
                cascade = CascadeType.ALL, 
                fetch = FetchType.LAZY
              )
   
    private Set<Role> roles;        
     
    // Getters, setters and Constructor       
     

角色类的代码

@Entity
public class Role 
    
    @Id
    @GeneratedValue
    private int roleId;
    private String role;  
    
    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;       
    
    // Getters, setters and Constructor
        
  
   POST request on Postman is        


    "id":101,
    "name": "rahul",
    "password": "456",
    "email": "rahul@gmail.com",
    "phoneNo": "1234561234",
    "role": [
        "role":"USER"
    ]

    
          
       

Code on Configuration part       
  
    @Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter 
    
     protected void configure(HttpSecurity http)throws Exception
     
        http.csrf().disable();
     


    @Bean
    public BCryptPasswordEncoder passwordEncoder()
    
        return new BCryptPasswordEncoder();
    
         

     
Code On Controller part
   
@RestController
public class AdminController 
    
    @Autowired
    UserRepository userRepo;

    @Autowired
    BCryptPasswordEncoder encryptPassword;

    @PostMapping("/admin/add")
    public String addUserByAdmin(@RequestBody User user)
    
        String pass = user.getPassword();
        String encrypt = encryptPassword.encode(pass);
        user.setPassword(encrypt);

        userRepo.save(user);
        return "User added Successfully";
    

 
    

角色表通过Jpa连接数据库

public interface RoleRepository extends JpaRepository<Role, Integer> 
    


   
     

用户表通过Jpa连接数据库

public interface UserRepository extends JpaRepository<User,Integer>
    

这里的问题是用户表被正确映射但角色表没有被映射。

roleId    role    user_id         
NULL      NULL    NULL 
  

我哪里错了?谁能帮帮我?

【问题讨论】:

你能分享一下你如何保存这个的代码(在服务上)吗? @junbetterway 我已经更新了代码。请仔细查看。 【参考方案1】:

在下面的控制器方法中,您是否尝试过调试传入的请求 User 对象?

无论如何,我有以下几点:

首先,查看您的请求正文,您的角色字段名为role,而您的用户对象有一个字段roles,因此,我很确定在您的处理过程中它是null,因为它不会由于字段名称不匹配而在那里反序列化。尝试将您的请求正文更改为以下内容:


    "id":101,
    "name": "rahul",
    "password": "456",
    "email": "rahul@gmail.com",
    "phoneNo": "1234561234",
    "roles": [
        "role":"USER"
    ]

其次,如果您检查您的数据库,角色将被保留,但是您的外键 user_id 为空。这是意料之中的。您对 User 对象所做的级联仅意味着(因为您使用 CascadeType.ALL)一旦您保存 User 对象,保存操作也将级联到 Role 对象但是,JPA 仍然需要知道关系,因此您必须为每个角色对象设置用户。因此,您可以将控制器方法更新为以下内容:

@PostMapping("/admin/add")
public String addUserByAdmin(@RequestBody User user)

  String pass = user.getPassword();
  String encrypt = encryptPassword.encode(pass);
  user.setPassword(encrypt);
  // JPA needs to know this relationship...
  user.getRoles().forEach(role -> role.setUser(user));
  userRepo.save(user);
  return "User added Successfully";

现在您可以尝试看看您的预期行为现在应该发生了。

其他建议:

为什么我们在用户请求中传递 ID 字段?您可以从您的请求正文中删除它并使用以下内容自动生成您的 ID,以避免您的所有实体出现唯一索引或主键违规异常:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;

您还可以删除映射上的targetEntity = Role.class,因为它仅用于泛型,并且对于您的情况,显然您没有将泛型用于 Set。更新您的 User 对象以进行角色映射:

   @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Set<Role> roles;   

最后,如果您可以将传入的有效负载包装到 DTO 中会更好,因为您不希望将实体/模型暴露给 API,但我认为这仅适用于您的测试环境。

【讨论】:

【参考方案2】:

在使用save() 时,您需要刷新对数据库的更改,请尝试以下操作:

userRepo.saveAndFlush(user);

【讨论】:

以上是关于子表在 JPA 中的 OneToMany 关系中没有映射的主要内容,如果未能解决你的问题,请参考以下文章

不加入子表的 JPA (@OneToMany) 查询

Jpa中ManyToMany和OneToMany的双向控制

Jpa中ManyToMany和OneToMany的双向控制

java JPA中的单向OneToMany关系

JPA:关于 OneToMany 关系中阻抗不匹配的问题

如何在 JPA 中定义单向 OneToMany 关系