One To Many with Parent composite primary key is part of child primary key issue. Throwing Exceptions with the below code snippets
Sample JSON Embedded Data as follows:
{
"pt_reg_no": "1000", //Serial number generation
"game_year": "G12021",
"name": "myname",
"eventDetails": [{
"major_event_code": "A",
"sub_event_code": "A7",
"category_code": "MO"
},
{
"major_event_code": "B",
"sub_event_code": "B7",
"category_code": "WO"
}
]
}
Participant can register for multiple Events:
Participant (Composite Key) - pt_reg_no, game_year
EventDetails (Composite Key) - pt_reg_no, game_year, sub_event_code, category_code
//Parent Class IDclass
public class ParticipantKey implements Serializable {
private Long pt_reg_no;
private String game_year;
}
@IdClass(ParticipantKey.class)
public class ParticipantModel {
@Id
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "participantseq"
)
@SequenceGenerator(
name = "participantseq",
allocationSize = 1
)
private Long pt_reg_no;
@Id
private String game_year = 'G12021';
@OneToMany(mappedBy = "participantModel", orphanRemoval = true, cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
private Set<EventDetailsModel> eventDetails = new HashSet<>();
public Set<EventDetailsModel> getEventDetails() {
return eventDetails;
}
public void setEventDetails(Set<EventDetailsModel> eventDetails) {
this.eventDetails = eventDetails;
for (EventDetailsModel b : eventDetails) {
b.setParticipantModel(this);
}
}
}
//Child class IDclass
public class ParticipantEventDetailsId implements Serializable {
private ParticipantKey participantModel;
private String sub_event_code;
private String category_code;
}
public class EventDetailsModel {
@Id
@Column(name = "sub_event_code")
private String sub_event_code;
@Id
@Column(name = "category_code")
private String category_code;
@Id
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumns({
@JoinColumn(name = "pt_reg_no", referencedColumnName = "pt_reg_no"),
@JoinColumn(name = "game_year", referencedColumnName = "game_year")
})
private ParticipantModel participantModel;
public ParticipantModel getParticipantModel() {
return participantModel;
}
public void setParticipantModel(ParticipantModel participantModel) {
this.participantModel = participantModel;
}
}
//---------------------------------------------------
//JSON input data received into ParticipantModel from @requestBody
public class FormDataObjects {
private ParticipantModel formData;
@JsonCreator
public FormDataObjects(ParticipantModel formData) {
this.formData = formData;
}
}
//Controller Entry point
@RequestMapping(path = "/participantData", method = RequestMethod.POST)
@Transactional
public ResponseEntity<?> participantRegistration(@Valid @RequestBody FormDataObjects values) {
ParticipantModel participant = values.getFormData();
participant.setGame_year(new SimpleDateFormat("yyyy").format(new Date()) GenricData.game);
ParticipantModel person = participantRepository.save(participant);
if (person == null) {
return ResponseEntity.ok("Participant is not inserted");
} else {
Set<EventDetailsModel> eventDetails = participant.getEventDetails();
if (eventDetails.size() > 0) {
eventDetails.forEach(event -> {
//event.setPt_reg_no(person.getPt_reg_no());
//event.setGame_year(person.getGame_year());
//event.setParticipantModel(participant);
entityManager.persist(event);
entityManager.flush();
entityManager.clear();
});
}
}
return ResponseEntity.ok("inserted");
}
CodePudding user response:
You can try a "derived identity" by mapping your details class like this:
public class ParticipantEventDetailsId implements Serializable {
private String sub_event_code;
private String category_code;
private ParticipantKey participantModel; // matches name of attribute and type of ParticipantModel PK
}
public class EventDetailsModel {
@Id
@Column(name = "sub_event_code")
private String sub_event_code;
@Id
@Column(name = "category_code")
private String category_code;
@Id
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumns({
@JoinColumn(name = "pt_reg_no", referencedColumnName = "pt_reg_no"),
@JoinColumn(name = "game_year", referencedColumnName = "game_year")
})
private ParticipantModel participantModel;
}
Derived identities are discussed (with examples) in the JPA 2.2 spec in section 2.4.1.
CodePudding user response:
Alternative solution to OneToMany mapping when parent has composite key and serial number generation is also required at parent
Use @Transient annotation at Set or List Child Entities
1)save Parent entity with above annotation helps jpa to skip List/Set of EventsDetailsModel from saving
2) Iterate Child and get Parent composite key values which are already saved and persist child data along with childs key attributes.
//Parent Class IDclass
public class ParticipantKey implements Serializable {
private Long pt_reg_no;
private String game_year;
}
@IdClass(ParticipantKey.class)
public class ParticipantModel {
@Id
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "participantseq"
)
@SequenceGenerator(
name = "participantseq",
allocationSize = 1
)
private Long pt_reg_no;
@Id
private String game_year = 'G12021';
@Transient //Find exact path for Transient
private Set<EventDetailsModel> eventDetails = new HashSet<>();
public Set<EventDetailsModel> getEventDetails() {
return eventDetails;
}
}
//Child class IDclass
public class ParticipantEventDetailsId implements Serializable {
private Long pt_reg_no;
private String game_year;
private String sub_event_code;
private String category_code;
}
public class EventDetailsModel {
@Id
@Column(name = "sub_event_code")
private String sub_event_code;
@Id
@Column(name = "category_code")
private String category_code;
@Id
private Long pt_reg_no;
@Id
private String game_year;
}
//---------------------------------------------------
//JSON input data received into ParticipantModel from @requestBody
public class FormDataObjects {
private ParticipantModel formData;
@JsonCreator
public FormDataObjects(ParticipantModel formData) {
this.formData = formData;
}
}
//Controller Entry point
@RequestMapping(path = "/participantData", method = RequestMethod.POST)
@Transactional
public ResponseEntity<?> participantRegistration(@Valid @RequestBody FormDataObjects values) {
ParticipantModel participant = values.getFormData();
participant.setGame_year(new SimpleDateFormat("yyyy").format(new Date()) GenricData.game);
ParticipantModel person = participantRepository.save(participant);
if (person == null) {
return ResponseEntity.ok("Participant is not inserted");
} else {
Set<EventDetailsModel> eventDetails = participant.getEventDetails();
if (eventDetails.size() > 0) {
eventDetails.forEach(event -> {
event.setPt_reg_no(person.getPt_reg_no());
event.setGame_year(person.getGame_year());
entityManager.persist(event);
entityManager.flush();
entityManager.clear();
});
}
}
return ResponseEntity.ok("inserted");
}