Reputation: 7381
I have a RESTcontroller that has a delete mapping like so:
@DeleteMapping("/deleterequest/{custId}")
//@Transactional
public ResponseEntity<?> delete(@PathVariable long custId) {
log.info("entering deleterequest");
LeaveQuery deleteLeaveQuery = leaveQueryRepository.findOne(custId);
log.info("condition" + deleteLeaveQuery.getStatus().equals("Onbehandeld"));
// if (!deleteLeaveQuery.getStatus().equals("Onbehandeld"))
// return ResponseEntity.badRequest().build();
//deleteLeaveQuery.setAccount(null);
//leaveQueryRepository.save(deleteLeaveQuery);
log.info("is deleteLeaveQuery null? " + (deleteLeaveQuery == null));
//leaveQueryRepository.delete(deleteLeaveQuery);
//leaveQueryRepository.delete(deleteLeaveQuery.getId());
leaveQueryRepository.deleteById(deleteLeaveQuery.getId());
accountService.sendLeaveRequestCanceledNotification(deleteLeaveQuery);
return ResponseEntity.ok().build();
}
When I use the regular (built-in) delete function of my leaveQueryRepository, I get no error, not during log INFO mode nor with log DEBUG mode on. However the object doesn't get deleted either. Its still in the database after the delete method was called. When I make a custom spring repository method called deleteById
I get the following error:
org.springframework.dao.InvalidDataAccessApiUsageException: No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call; nested exception is javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call
at
I have no idea what is causing this error. The jparepository looks like this:
@Repository
public interface LeaveQueryRepository extends JpaRepository<LeaveQuery, Long> {
//@Modifying
public void deleteById(long id);
}
The LeaveRequest object looks like this:
@Entity
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id",
scope = LeaveQuery.class)
public class LeaveQuery implements Serializable {
@Id
@GeneratedValue
private Long id;
private Date startDate;
private Date endDate;
private String status = "Onbehandeld";
private String reason ="";
private int totalHours;
private String processedBy;
@ManyToOne(fetch = FetchType.EAGER) //, cascade = CascadeType.PERSIST
@JoinColumn(name = "FK_account", nullable = true)
private Account account;
public String getProcessedBy() {
return processedBy;
}
public void setProcessedBy(String processedBy) {
this.processedBy = processedBy;
}
public int getTotalHours() {
return totalHours;
}
public void setTotalHours(int totalHours) {
this.totalHours = totalHours;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
@Override
public String toString() {
return "LeaveQuery{" +
"id=" + id +
", startDate=" + startDate +
", endDate=" + endDate +
", denialReason='" + reason + '\'' +
'}';
}
}
It has a relation with an Account object which looks like this:
@Entity
//@JsonIgnoreProperties
//@JsonIdentityInfo(
// generator = ObjectIdGenerators.PropertyGenerator.class,
// property = "id",
// scope = Account.class)
public class Account implements Serializable {
@Id
@GeneratedValue
private Long id;
private String username;
private String password;
private String name;
private boolean admin;
private boolean enabled;
private int remainingStatutoryLeaveHours = 240;
private int remainingNonStatutoryLeaveHours = 60;
@JsonIgnore
@OneToMany(fetch = FetchType.EAGER, mappedBy = "account", cascade = CascadeType.ALL)
List<LeaveQuery> leaveQueryList;
//
@OneToMany(fetch = FetchType.LAZY, mappedBy = "account", cascade = CascadeType.ALL)
List<LaborPeriod> laborperiods = new ArrayList<>();
@OneToOne
private Person person;
@Enumerated
UserRole userRole = UserRole.USER;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public UserRole getUserRole() {
return userRole;
}
public void setUserRole(UserRole userRole) {
this.userRole = userRole;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isAdmin() {
return admin;
}
public void setAdmin(boolean admin) {
this.admin = admin;
}
public List<LaborPeriod> getLaborperiods() {
return laborperiods;
}
public void setLaborperiods(List<LaborPeriod> laborperiods) {
this.laborperiods = laborperiods;
}
public List<LeaveQuery> getLeaveQueryList() {
return leaveQueryList;
}
public void setLeaveQueryList(List<LeaveQuery> leaveQueryList) {
this.leaveQueryList = leaveQueryList;
}
public int getRemainingStatutoryLeaveHours() {
return remainingStatutoryLeaveHours;
}
public void setRemainingStatutoryLeaveHours(int remainingStatutoryLeaveHours) {
this.remainingStatutoryLeaveHours = remainingStatutoryLeaveHours;
}
public int getRemainingNonStatutoryLeaveHours() {
return remainingNonStatutoryLeaveHours;
}
public void setRemainingNonStatutoryLeaveHours(int remainingNonStatutoryLeaveHours) {
this.remainingNonStatutoryLeaveHours = remainingNonStatutoryLeaveHours;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", name='" + name + '\'' +
", admin=" + admin +
", enabled=" + enabled +
", remainingStatutoryLeaveHours=" + remainingStatutoryLeaveHours +
", remainingNonStatutoryLeaveHours=" + remainingNonStatutoryLeaveHours +
", userRole=" + userRole +
'}';
}
}
Does anyone know what could be causing this error?
Any help would be appreciated.
Upvotes: 2
Views: 2227
Reputation: 50
All controller methods should be none transactional. You should add one more layer between Controller and Repository (Service layer) and put @Transactional on Service class or put this annotation on your method in this Service class.
It should be Controller -> Service -> Repository
To let @Transactional work you should init TransactionalManager. You can add something like this in your Persistence Configuration
@Bean
public JpaTransactionManager transactionManager() throws IOException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
Upvotes: 3
Reputation: 12552
Use orphanRemoval = true
.
Try to update your Account
class like so
@JsonIgnore
@OneToMany(fetch = FetchType.EAGER, mappedBy = "account", cascade = CascadeType.ALL, orphanRemoval = true)
List<LeaveQuery> leaveQueryList;
Also check out this question.
Upvotes: 1