在Spring中以一对多关系传递新对象



例如,我有一个User实体,它与Role实体有@ManyToMany关系。此外,还有一个控制器在DB中保存一个新用户,该控制器接收一个User@RequestBody。因此,我需要在json主体请求中传递一些Roles,以将它们附加到我发送的用户。这是我的问题:

如何传递尚未保存在DB中的角色事实上,我正在寻找一种方法,在通过用户请求后立即保存角色。据我所知,例如,当我想发送新用户保存在DB中时,如果是这样的话:

{
"username" : "user1",
"password" : "pwd",
"roles" : [
{
"label" : "ROLE_ADMIN"
}
]

它不起作用,因为此结构希望获得现有角色的列表,而不是当前尚未保存的角色。因此,它必须以这种方式工作:

{
"username" : "user1",
"password" : "pwd",
"roles" : [
{
"id" : "6"
"label" : "ROLE_ADMIN"
}
]

这个id属性应该引用数据库中的某一行

MyController:


@RestController
@RequestMapping(value = "/Users")
public class UserController {

@Autowired
UserRepository userRepository;

@RequestMapping(value = "/Add",method = POST)
@ResponseBody
private Response AddUser(@RequestBody User user){
return new Response("Add single user " ,
HttpStatus.OK.value(),
userRepository.save(user));
}
}

用户实体:



@Entity(name = "USER_TBL")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class User {
@Id
@GeneratedValue
private long id;
private String username;
private String password;
public User() {
}

@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(name = "User_role" ,joinColumns =
@JoinColumn ( name = " user_id" ), inverseJoinColumns =
@JoinColumn(name = "role_id"))
List<Role> roleList;
public List<Role> getRoleList() {
return roleList;
}
public void setRoleList(List<Role> roleList) {
this.roleList = roleList;
}

public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}

public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}

角色实体:



@Entity(name = "tbl_roles")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class Role {
@Id
@GeneratedValue
private long id;
@Column(unique = true)
String label;
public Role() {
}
@ManyToMany(fetch=FetchType.EAGER,mappedBy = "roleList")
List<User> users ;
public Role(String label) {
this.label = label;
}

public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
}

好的,鉴于您提供的信息,我首先建议您为此创建一个Service类,这是为了将控制器与存储库操作分离

@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Transactional
private User addUser(User user){
...
}
}

SN:强烈建议不要在字段级注入中使用@Autowired(例如,如上所述使用构造函数注入(

至于addUser方法(用transactional注释(,首先应该检索所有角色(我会选择这个选项,因为我认为角色表不会很大,否则你应该为列表中的每个角色查找ByRoleName(((。

List<Role> persistedRoleList = rolesRepository.findAll();

此时,过滤所有已经持久化的角色,并将其添加到一个单独的列表中(您不必持久化这些角色(

List<Role> existingRoles = user.getRoleList().stream()
.filter(persistedRoleList::contains)
.map(role -> persistedRoleList.get(persistedRoleList.indexOf(role)))
.collect(Collectors.toList());

正如你所看到的,我使用了"contains"one_answers"get(indexOf((("方法,这意味着你在角色的类中正确地重写了equals方法,也是如此

public class Role {

...
@Override
public boolean equals(Object o) {
return o instanceof Role && this.label.equals(((Role) o).getLabel());
}
}

这当然非常有效,因为很明显,角色有一个独特的标签字段

在点击"保存"方法之前,您必须删除已经保留的角色,以便

user.getRoleList().removeAll(existingRoles);

这样一来,最终新用户将拥有带id的所有现有角色,以及不带id的不存在角色。你现在缺少的是关系的级联

所以在用户中,你会有

@ManyToMany(fetch=FetchType.EAGER, cascade = CascadeType.PERSIST)

在任职期间,您将获得

@ManyToMany(fetch=FetchType.LAZY, cascade = CascadeType.PERSIST)

SN:重要的是LAZY部分。您应该尽量避免关系船两侧的Eagle,这可能会在映射对象时导致循环。

现在只有

userRepository.save(user);

最后,从.save((方法中,您将返回类型为User的持久化实体,该实体在Transactional方法中,只需执行

persistedUser.getRoleList().addAll(existingRoles);

添加已经存在的角色并将其映射到用户(也是数据库(

全类:

@Service
public class UserService {

private final UserRepository userRepository;

private final RoleRepository roleRepository;

public UserService(UserRepository userRepository, RoleRepository roleRepository) {
this.userRepository = userRepository;
this.roleRepository = roleRepository;
}

@Transactional
public User addUser(User user) {
List<Role> persistedRoleList = Optional.of(roleRepository.findAll()).orElse(new ArrayList<>());
List<Role> existingRoles = user.getRoleList().stream()
.filter(persistedRoleList::contains)
.map(role -> persistedRoleList.get(persistedRoleList.indexOf(role)))
.collect(Collectors.toList());

user.getRoleList().removeAll(existingRoles);
User persistedUser = userRepository.save(user);
persistedUser.getRoleList().addAll(existingRoles);
return persistedUser;
}
}

编辑:我修改了答案,因为我试图保存一个已经持久化的实体这一事实存在漏洞

最新更新