Spring Boot双向OneToMany关联POST请求中Playlist的user字段为null问题解决
Spring Boot双向OneToMany关联POST请求中Playlist的user字段为null问题解决
在实现Spring Boot双向OneToMany关联时,创建用户同时传入新Playlist数据,返回的Playlist对象中user字段为null,无法建立内存中的双向关联。
User实体类
@Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id ; private String username ; private String password ; private String email ; private String firstname ; private String lastname ; @OneToMany( mappedBy = "user" , cascade = CascadeType.ALL , orphanRemoval = true ) private List<Playlist> playlists = new ArrayList<>() ; // getters and setters }
Playlist实体类
@Entity @Table(name = "playlist") public class Playlist { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String description; @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "user_id") private User user; // getters and setters }
UserController的POST方法
@RestController @RequestMapping("/api/users") public class userController { @Autowired UserService userService ; // ... other controller mappings @PostMapping("") public User createUser(@RequestBody User reqUser){ return userService.createUser(reqUser) ; } }
UserService的createUser方法
@Service public class UserService { @Autowired UserRepo userRepo ; public List<User> getAllUsers() { List <User> users = new ArrayList<>() ; userRepo.findAll().forEach(users::add); return users ; } public User createUser(User reqUser) { User newUser = new User() ; newUser.setUsername(reqUser.getUsername()); newUser.setEmail(reqUser.getEmail()); newUser.setPassword(reqUser.getPassword()); newUser.setFirstname(reqUser.getFirstname()); newUser.setLastname(reqUser.getLastname()); // adding playlists List<Playlist> playlists = new ArrayList<>() ; reqUser.getPlaylists().forEach(playlists::add); newUser.setPlaylists(playlists); userRepo.save(newUser) ; return newUser ; } }
请求JSON
{ "username" : "poodie" , "password" : "randomPasswrod" , "firstname" : "Raj" , "lastname" : "Bhushan" , "playlists" : [ { "name" : "playlist-01" , "description" : "first playlist" } , { "name" : "playlist-01" , "description" : "first playlist" } ] }
响应JSON
{ "id": 12, "username": "poodie", "password": "randomPasswrod", "email": null, "firstname": "Raj", "lastname": "Bhushan", "playlists": [ { "id": 9, "name": "playlist-01", "description": "first playlist", "user": null, "songs": [] }, { "id": 10, "name": "playlist-02", "description": "first playlist", "user": null, "songs": [] } ] }
问题原因
在双向OneToMany关联中,@OneToMany的mappedBy = "user"指定了Playlist是关联的维护端(即外键user_id由Playlist实体管理)。当前代码只设置了User的playlists集合,但没有给每个Playlist对象设置对应的user属性,导致内存中的Playlist对象和User对象的双向关联没有建立。虽然级联保存会把User的id写入Playlist的user_id字段(数据库中关联是正确的),但返回的是保存前构造的内存对象,其中Playlist的user字段为null。
修复方案1:维护双向关联的一致性(推荐)
在User实体中添加辅助方法,用于添加Playlist时自动设置关联的User,确保双向关联同步:
@Entity @Table(name = "users") public class User { // ... 原有字段 @OneToMany( mappedBy = "user" , cascade = CascadeType.ALL , orphanRemoval = true ) private List<Playlist> playlists = new ArrayList<>() ; // 添加辅助方法 public void addPlaylist(Playlist playlist) { playlists.add(playlist); playlist.setUser(this); // 关键:设置Playlist的user属性 } // getters and setters }
修改UserService中的createUser方法,使用这个辅助方法添加Playlist:
public User createUser(User reqUser) { User newUser = new User() ; newUser.setUsername(reqUser.getUsername()); newUser.setEmail(reqUser.getEmail()); newUser.setPassword(reqUser.getPassword()); newUser.setFirstname(reqUser.getFirstname()); newUser.setLastname(reqUser.getLastname()); // 改用addPlaylist方法添加 for (Playlist playlist : reqUser.getPlaylists()) { newUser.addPlaylist(playlist); } userRepo.save(newUser) ; return newUser ; }
这样保存后,内存中的Playlist对象就会持有正确的User引用,返回的JSON中user字段就不会为null。
修复方案2:保存后从数据库重新查询
如果不想修改实体类,也可以在保存User后,从数据库中重新查询该User返回。因为数据库中的关联关系已经正确建立,查询出来的对象会自动填充Playlist的user属性:
public User createUser(User reqUser) { User newUser = new User() ; newUser.setUsername(reqUser.getUsername()); newUser.setEmail(reqUser.getEmail()); newUser.setPassword(reqUser.getPassword()); newUser.setFirstname(reqUser.getFirstname()); newUser.setLastname(reqUser.getLastname()); List<Playlist> playlists = new ArrayList<>() ; reqUser.getPlaylists().forEach(playlists::add); newUser.setPlaylists(playlists); // 保存后重新查询 User savedUser = userRepo.save(newUser) ; return userRepo.findById(savedUser.getId()).orElse(savedUser); }
内容的提问来源于stack exchange,提问作者humblefool
相关产品推荐
相关产品推荐

