Issue
I have a question and it is related to the error that I am getting. How bad is it really to have a circular reference in my service? I know very well what the error is due to and how to possibly solve it, only that in the company where I work a Senior recommended me that for transactional issues it is necessary to make such a circular reference and in fact it is a very recurrent practice there, but as I am starting a personal project from scratch is the first time I get the error and it triggered the doubt again. Thank you very much in advance!
Here is the code of the service
public class MedicalRecordServiceImpl implements MedicalRecordService {
private final MedicalRecordRepository medicalRecordRepository;
private final MedicalRecordService medicalRecordService;
private final PatientService patientService;
private final TutorService tutorService;
private final MedicalHistoryAnswerService medicalHistoryAnswerService;
private final DentalHistoryAnswerService dentalHistoryAnswerService;
public MedicalRecordServiceImpl(MedicalRecordRepository medicalRecordRepository, MedicalRecordService medicalRecordService, PatientService patientService, TutorService tutorService, MedicalHistoryAnswerService medicalHistoryAnswerService, DentalHistoryAnswerService dentalHistoryAnswerService) {
this.medicalRecordRepository = medicalRecordRepository;
this.medicalRecordService = medicalRecordService;
this.patientService = patientService;
this.tutorService = tutorService;
this.medicalHistoryAnswerService = medicalHistoryAnswerService;
this.dentalHistoryAnswerService = dentalHistoryAnswerService;
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void saveMedicalRecord(MedicalRecordEntity medicalRecord) {
medicalRecordRepository.save(medicalRecord);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public ResponseEntity<?> createNewMedicalRecord(MedicalRecordDTO medicalRecordDTO) {
PatientEntity patient = this.storeMedicalRecordIntoPatient(medicalRecordDTO);
TutorEntity tutor = this.storeMedicalRecordIntoTutor(medicalRecordDTO);
List<MedicalHistoryAnswerEntity> medicalHistoryAnswers = this.storeMedicalRecordIntoMedicalHisAns(medicalRecordDTO);
List<DentalHistoryAnswerEntity> dentalHistoryAnswers = this.storeMedicalRecordIntoDentalHisAns(medicalRecordDTO);
patientService.savePatient(patient);
tutor.setPatient(patient);
tutorService.saveTutor(tutor);
MedicalRecordEntity medicalRecord = this.createMedicalRecord(patient, tutor);
medicalRecordService.saveMedicalRecord(medicalRecord);
medicalHistoryAnswers.forEach(medicalHistoryAnswer -> {
medicalHistoryAnswer.setMedicalRecord(medicalRecord);
medicalHistoryAnswerService.saveMedicalHistoryAnswer(medicalHistoryAnswer);
});
dentalHistoryAnswers.forEach(dentalHistoryAnswer -> {
dentalHistoryAnswer.setMedicalRecord(medicalRecord);
dentalHistoryAnswerService.saveDentalHistoryAnswer(dentalHistoryAnswer);
});
return ResponseEntity.status(HttpStatus.OK).body("");
}
}
Solution
The only reason why you may need circular dependency is the case when you what to access to "this" as to a bean to trigger annotated method logic.
For example if you have two methods "foo" (annotated with @Transactional) and "bar" (invokes "foo" within). You will have to use self injection to trigger transaction in case of invocation bar>foo (selfBean.foo() instead of this.foo()).
Also you can use @Lasy for self injection to avoid the circular dependency error.
But it's a pretty ugly solution and you should avoid it if it's possible. It depends on the situation, may be it's possible to split logic to different services or use TransactionTemplate.
Answered By - Dima G.
Answer Checked By - Willingham (JavaFixing Volunteer)