英文:
Issue updating Entity converted from DTO using ModelMapper in Spring Boot Service
问题
I am building a Spring Boot Service and trying to use ModelMapper to convert between DTO and Entity, but hitting issues on update. Here is a simplified example:
@Data
public class TeamDto {
	private String name;
	private List<PersonDto> members;
}
@Data
public class PersonDto {
	private String name;
}
@Data
@Entity
public class Team {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
	private String name;
	@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
	@LazyCollection(LazyCollectionOption.FALSE)
	@JoinColumn(name = "team_id")
	private List<Person> members = new ArrayList<>();
}
@Data
@Entity
public class Person {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
	private String name;
}
public interface TeamRepository extends ListCrudRepository<TeamEntity, Long> {}
@Configuration
public class ModelMapperConfig {
	@Bean
	ModelMapper getModelMapper() {
		return new ModelMapper();
	}
}
@RestController
@RequiredArgsConstructor
public class TeamController {
	private final TeamRepository teamRepository;
	private final ModelMapper mapper;
	@PostMapping("/team")
	public void create(@RequestBody TeamDto team) {
		Team teamEntity = mapper.map(team, Team.class);
		teamRepository.save(teamEntity);
	}
	@PutMapping("/team/{id}")
	public void update(@RequestBody TeamDto team, @PathVariable Long id) {
		Team teamEntity = teamRepository.findById(id).orElseThrow(() -> new ResponseStatusException(NOT_FOUND));
		mapper.map(team, teamEntity);
		teamRepository.save(teamEntity);
	}
}
I am able to create a team, but when I try to update, I get an error saying: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: org.aero.cvr.TeamEntity.members.
I'm not sure how best to address this error.
英文:
I am building a Spring Boot Service and trying to use ModelMapper to convert between DTO and Entity, but hitting issues on update. Here is a simplified example:
@Data
public class TeamDto {
private String name;
private List<PersonDto> members;
}
@Data
public class PersonDto {
private String name;
}
@Data
@Entity
public class Team {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
@JoinColumn(name = "team_id")
private List<Person> members = new ArrayList<>();
}
@Data
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
public interface TeamRepository extends ListCrudRepository<TeamEntity, Long> {}
@Configuration
public class ModelMapperConfig {
@Bean
ModelMapper getModelMapper() {
return new ModelMapper();
}
}
@RestController
@RequiredArgsConstructor
public class TeamController {
private final TeamRepository teamRepository;
private final ModelMapper mapper;
@PostMapping("/team")
public void create(@RequestBody TeamDto team) {
Team teamEntity = mapper.map(team, Team.class);
teamRepository.save(teamEntity);
}
@PutMapping("/team/{id}")
public void update(@RequestBody TeamDto team, @PathVariable Long id) {
Team teamEntity = teamRepository.findById(id).orElseThrow(() -> new ResponseStatusException(NOT_FOUND));
mapper.map(team, teamEntity);
teamRepository.save(teamEntity);
}
}
I am able to create a team, but when I try to update, I get an error saying: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: org.aero.cvr.TeamEntity.members.
I'm not sure how best to address this error.
答案1
得分: 1
Here is the translated code portion:
最佳解决方案是不使用ModelMapper来处理成员列表,而是让它跳过该字段:
@Bean
ModelMapper getModelMapper() {
    ModelMapper mapper = new ModelMapper();
    mapper.typeMap(TeamDto.class, TeamEntity.class)
        .addMappings(mp -> mp.skip(TeamEntity::setMembers));
    return mapper;
}
然后手动处理该字段,更新现有列表,而不是让ModelMapper替换它,但仍然在列表中使用ModelMapper处理对象:
teamEntity.getMembers().clear();
teamDto.getMembers().stream().map(dto -> mapper.map(dto, Person.class))
    .forEach(teamEntity.getMembers()::add);
英文:
Best solution I've come up with is to not use ModelMapper to handle the members list. Instead, have it skip that field:
    @Bean
ModelMapper getModelMapper() {
ModelMapper mapper = new ModelMapper();
mapper.typeMap(TeamDto.class, TeamEntity.class)
.addMappings(mp -> mp.skip(TeamEntity::setMembers));
return mapper;
}
and to handle the field manually, updating the existing list, rather than letting ModelMapper replace it, but still using ModelMapper on the objects in the list:
	teamEntity.getMembers().clear();
teamDto.getMembers().stream().map(dto -> mapper.map(dto, Person.class))
.forEach(teamEntity.getMembers()::add);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论