我有两个实体有多对多关系:
权限(AbstractActiveEntity只有两个字段,Long Id和boolean Active):
@Entity(name = "Permission")
@NoArgsConstructor
@SuperBuilder(toBuilder = true)
@Table(name = "permission")
@AllArgsConstructor
@Getter
@Setter
@ToString
public class Permission extends AbstractActiveEntity {
String code;
@ManyToMany(
mappedBy = "permissions",
fetch = FetchType.LAZY,
cascade = {MERGE},
targetEntity = Role.class
)
@ToString.Exclude
private Set<Role> roles = new HashSet<>();
//equals and hashcode
}
此角色实体:
@Getter
@SuperBuilder(toBuilder = true)
@Entity
@Setter
@ToString
@RequiredArgsConstructor
public class Role extends AbstractActiveEntity {
private String name;
@ManyToMany(cascade = {MERGE})
@JoinTable(
name = "roles_permissions",
joinColumns = {@JoinColumn(name = "role_id")},
inverseJoinColumns = {@JoinColumn(name = "permission_id")}
)
private Set<Permission> permissions = new HashSet<>();
//equals and hashcode
}
这是我的更新方法:
public PermissionDto update(@Valid PermissionDto permissionDto) {
Permission permissionEntity = permissionMapper.toEntity(permissionDto);
return permissionMapper.toDto(permissionRepository.save(permissionEntity));
}
更新API:
@PatchMapping
public PermissionDto update(@RequestBody @Valid PermissionDto permissionDto) {
return permissionService.update(permissionDto);
}
PermissionDto:
@Getter
@Setter
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
public class PermissionDto extends AbstractActiveDto {
@NotBlank
private String code;
private Set<Long> rolesIds = new HashSet<>();
}
职责:
@NoArgsConstructor
@SuperBuilder(toBuilder=true)
@Data
public class RoleDto extends AbstractActiveDto {
@NotBlank
private String name;
@ToString.Exclude
private Set<Long> permissionsIds;
}
PermissionMapper:
@Mapper(componentModel = "spring",
unmappedTargetPolicy = ReportingPolicy.WARN,
builder = @Builder(disableBuilder = true),
uses = RoleMapper.class)
public interface PermissionMapper extends EntityMapper<Permission, PermissionDto> {
@Override
@Mapping(source = "rolesIds", target = "roles")
Permission toEntity(PermissionDto dto);
@Override
@Mapping(source = "roles", target = "rolesIds")
PermissionDto toDto(Permission entity);
@AfterMapping
default void assignPermissionToRoles(@MappingTarget Permission permission) {
var permissionIdSet = new HashSet<Permission>();
permissionIdSet.add(permission);
permission.getRoles().forEach(role -> role.setPermissions(permissionIdSet));
}
}
角色Map器:
@Mapper(componentModel = "spring",
unmappedTargetPolicy = ReportingPolicy.WARN,
uses = PermissionMapper.class)
public abstract class RoleMapper {
@Autowired
private RoleRepository roleRepository;
public abstract Role toEntity(RoleDto dto);
public abstract RoleDto toDto(Role entity);
Set<Role> mapRolesIdsToRoles(Set<Long> rolesIds) {
return rolesIds.stream()
.map(roleId -> roleRepository.findById(roleId).orElseThrow(
() -> new ResourceNotFoundException("Role with ID %d not found".formatted(roleId))
))
.collect(Collectors.toSet());
}
Set<Long> mapRolesToRolesIds(Set<Role> roles) {
return roles.stream().map(Role::getId).collect(Collectors.toSet());
}
}
当我试图更新一个已有的权限,而这个权限有一个与之相关的角色时,hibernate不会删除当前的关系并插入新的关系,它只会插入新的关系。
例如,如果我有一个与ID为1的Role相关的权限,我试图通过传递以下JSON来更新它:
{
"id": 15991,
"active": true,
"code": "NEW_ROLE",
"rolesIds": [
2
]
}
最后,连接表中有两行,一行是roleId 1,另一行是roleId 2。
我希望在每次更新时刷新角色关系。
2条答案
按热度按时间cu6pst1q1#
你们的关系不对称。如果您更改:
以及:
然后更新将正确传播。
rqcrx0a62#
因此,当你试图保存
permissionEntity
(不获取其引用)时,Hibernate生成了几个查询:1.按id(
15991
)查询选择是否插入或更新->已存在!1.更新
permissionEntity
的所有列Set<Role> roles
中只有一个项目,这是一个新的对象引用->插入到关系表。为了解决这个问题,让我们通过获取实体来更新服务,而不是从dtoMap它们。
你可以参考这个doc。