I am using Spring Data JPA to process database calls. For this purpose, I have created:
An EmployeeRepository interface, which extends a
JpaRepository<Employee, Long>An EmployeeService, which defines three methods:
Employee saveEmployee(Employee employee); Optional<Employee> getEmployee(Long id); Long deleteEmployee(Long id);An implementation of the EmployeeService:
@Override public Employee saveEmployee(Employee employee) { return employeeRepository.save(employee); } @Override public Optional<Employee> getEmployee(Long id) { return employeeRepository.findEmployeeById(id); } @Override public Long deleteEmployee(Long id) { employeeRepository.deleteById(id); return id; }
The issue is the following:
The get-methods work fine and can return an optional. The save-method, on the other hand, cannot return an optional. Apparently the JpaRepository returns an instance of the saved object upon calling save(). I would rather return an optional, since something could go wrong when saving the employee and in that case, I would like to throw an error - i.e. whenever the optional is not present, I throw an error.
The same holds for the delete-operation: What, for example, if I ask to delete an employee and pass in an id, which does not exist? I would like to catch this error and only then return the passed in id, if the delete operation was successfull. Which error would I have to catch for this purpose? Can someone explain this to me?
=================================================
update:
I have fixed the problem with the delete-call by simply checking if the given employee-id exists before calling `deleteById(id); if it doesn't, the service returns null, if it does, it return the id. The controller looks like this:
@DeleteMapping("/{id}") public ResponseEntity<Long> deleteEmployee(@PathVariable Long id) { Long deletedEmployeeId = employeeService.deleteEmployee(id); if (deletedEmployeeId != null) { return ResponseEntity.ok(deletedEmployeeId); } else { return ResponseEntity.status(HttpStatus.BAD_REQUEST); }
I am missing the DataAccessException, however. So, can it be that I would actually have to do the following:
@DeleteMapping("/{id}")
public ResponseEntity<Long> deleteEmployee(@PathVariable Long id) {
try {
Long deletedEmployeeId = employeeService.deleteEmployee(id);
if (deletedEmployeeId != null) {
return ResponseEntity.ok(deletedEmployeeId);
} else {
return ResponseEntity.status(HttpStatus.BAD_REQUEST);
}
} catch (DataAccessException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
}
This looks a bit like an over-kill to be honest.
I am still a bit unsure how to deal with the save-call. Before I posted this question, my controller was simply doing the following:
@PostMapping public ResponseEntity<Employee> saveEmployee(@RequestBody Employee employee) { return ResponseEntity.ok(employeeService.saveEmployee(employee)); }
What happens, if employeeService.saveEmployee(employee) throws a DataAccessException? Am I still returning a HTTP-status-code of 200, as I wrap the response in an ResponseEntity.ok() ?
If so, I would suggest to do the following:
@PostMapping
public ResponseEntity<Employee> saveEmployee(@RequestBody Employee employee) {
try {
Employee savedEmployee = employeeService.saveEmployee(employee);
return ResponseEntity.ok(savedEmployee);
} catch (DataAccessException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Is this something people do? Or are DataAccessExceptions usually neglected as they are not expected?