Issue
I want to import Profiles, that have a set of Professions, and a set of ProfessionGroups. The Professions are distributed accross the ProfessionGroups.
Following Entities are defined:
@Entity
public class Profile extends BaseEntity<Profile> { // B.E. defines id, creation_time,etc..
@OneToMany(cascade = CascadeType.ALL)
private Collection<Profession> professions;
@OneToMany(cascade = CascadeType.ALL)
private Collection<ProfessionGroup> professionGroups;
// .. getters and setters
}
@Entity
private class Profession extends BaseEntity<Profession> {
@Column(unique = true)
private String name;
// getters and setters
}
@Entity
public class ProfessionGroup extends BaseEntity<ProfessionGroup> {
@Column(unique = true)
private String name;
@ManyToOne(cascade = CascadeType.All)
private Collection<Profession> professions;
// getters and setters
}
Following code reads in some profiles serialized as json and wants to store it into the database:
// ...
Profile p = ...; // read from json using some deserializer
p.getProfessionGroups().forEach(pg -> pg.setProfessions(p.getProfessions());
// ..
ProfileService profileService = ...; //
profileService.save(profile);
The ProfileService calls internally entityManager.persist(...). The problem here is, that I get an "duplicate key value violates unique constraint" whenever i want to distribute all professions to all professionGroups. what can i do to safely store the profile, without getting a unique key constraint violation. JPA obviously wants to create a new professions for each entry in the professiongroups. However, the reference(s) to the profession(s) are the same. calling merge(...) didn't do the trick.
Solution
the solution can be found sometimes somewhere else:
the relationship between the entities 'profession' and 'professiongroup' is wrong. it should have been:
@Entity
public class ProfessionGroup extends BaseEntity<ProfessionGroup> {
@Column(unique = true)
private String name;
@ManyToMany(cascade = CascadeType.All)
private Collection<Profession> professions;
// getters and setters
// ..
}
a profession can be in one or more profession-groups, as a profession-group could have one or more profession. having this fixed, and adapting the valuable answer from @maress the solution now looks like this:
Profile profile = mapper.readValue(json, Profile.class);
List<Profession> managedProfessions = profile
.getProfessions()
.stream()
.map(p -> {
return professionService.update(p);
})
.map(Optional::get)
.collect(Collectors.toList());
profile.setProfessions(managedProfessions);
profile.getProfessiongroups().forEach(professionGroup -> {
professionGroup.setProfessions(managedProfessions);
});
profileService.save(profile);
piece of cake.
Answered By - phobos
Answer Checked By - Gilberto Lyons (JavaFixing Admin)