I am using Spring, Spring MVC, Spring Data, Hibernate, Maven I have seen similar question but the solutions didn't help me, so I decided to ask about it again. I have an application which should save a patient to doctor via a visit, but when I try add patient I got error. Thanks for help! Stacktrace:
Exception
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.virtualdent.entity.Visit; nested exception is javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.virtualdent.entity.Visit
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1013)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)
javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
Root Cause
org.springframework.orm.jpa.JpaSystemException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.virtualdent.entity.Visit; nested exception is javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.virtualdent.entity.Visit
org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:407)
org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528)
org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
com.sun.proxy.$Proxy50.save(Unknown Source)
com.virtualdent.service.PatientServiceImpl.savePatient(PatientServiceImpl.java:32)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
java.base/java.lang.reflect.Method.invoke(Unknown Source)
org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
com.sun.proxy.$Proxy61.savePatient(Unknown Source)
com.virtualdent.controller.PatientController.savePatient(PatientController.java:71)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
java.base/java.lang.reflect.Method.invoke(Unknown Source)
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)
javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
My entities:
@Entity
@Table
public class Visit implements Serializable {
private static final long serialVersionUID = -135088128548004469L;
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
private Integer id;
@Column
private String day;
@Column
private String time;
@ManyToMany(cascade={CascadeType.DETACH,CascadeType.PERSIST,CascadeType.REFRESH}, fetch=FetchType.EAGER)
private List<Dentist>dentists;
@OneToOne(mappedBy="visitDay",cascade= {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH})
private Patient patient;
public Visit() {}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDay() {
return day;
}
public void setDay(String day) {
this.day = day;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public List<Dentist> getDentists() {
return dentists;
}
public void setDentists(List<Dentist> dentists) {
this.dentists = dentists;
}
@Override
public String toString() {
return "Wizyta dnia: "+ day+" o godzinie:" + time;
}
public void addDentist(Dentist dentist)
{
if(dentists==null)
{
dentists=new ArrayList<>();
}
dentists.add(dentist);
}
public Patient getPatient() {
return patient;
}
public void setPatient(Patient patient) {
this.patient = patient;
}
//standard hashcode and equals()
}
@Entity
@Table
public class Patient {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
private Integer id;
@OneToOne(cascade=CascadeType.ALL)
private Visit visitDay;
@Column
private String firstName;
@Column
private String lastName;
@Column
private int number;
@Column
private String address;
public Patient() {
super();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Visit getVisitDay() {
return visitDay;
}
public void setVisitDay(Visit visitDay) {
this.visitDay = visitDay;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
//standard hash code and equals()
}
@Entity
@Table(name="dentysta")
public class Dentist implements Serializable{
private static final long serialVersionUID = 3128830699411486597L;
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
private Integer id;
@Column
private String firstName;
@Column
private String lastName;
@Column
private String specialization;
@Column
private int number;
@Column
private String address;
@ManyToMany(mappedBy="dentists", cascade=CascadeType.ALL)
@LazyCollection(LazyCollectionOption.FALSE)
private List<Visit>visits;
public Dentist() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getSpecialization() {
return specialization;
}
public void setSpecialization(String specialization) {
this.specialization = specialization;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<Visit> getVisits() {
return visits;
}
public void setVisits(List<Visit> visits) {
this.visits = visits;
}
public void addVisit(Visit visit)
{
if(visits==null)
{
visits=new ArrayList<>();
}
visit.addDentist(this);
visits.add(visit);
}
//standard hashcode and equals()
}
}
My controller:
@Controller
@RequestMapping("/patient")
public class PatientController {
@Autowired
private DentistService dentistService;
@Autowired
private PatientService patientService;
@Autowired
private VisitService visitService;
@RequestMapping("/home")
public String home(Model model)
{
List<Dentist>dentists=dentistService.getDentists();
model.addAttribute("dentists",dentists);
return "patient-home";
}
@RequestMapping("/showPatientForm")
public String showForm(@RequestParam Integer id, Model model)
{
Dentist dentist=dentistService.getDentist(id);
List<Visit>visits=dentist.getVisits();
model.addAttribute("visits",visits);
return "choose-visit-form";
}
@RequestMapping("/saveVisit")
public String saveVisit(@RequestParam("visitId") Integer visitId,Model model)
{
Visit visit=visitService.getVisit(visitId);
visitService.saveVisit(visit);
model.addAttribute("patient",new Patient());
model.addAttribute("visit",visit);
return "patient-form";
}
@RequestMapping("/savePatient")
public String savePatient(@RequestParam Integer visitId, @ModelAttribute("patient") Patient patient)
{
Visit visit=visitService.getVisit(visitId);
patient.setVisitDay(visit);
visit.setPatient(patient);
patientService.savePatient(patient);
return "redirect:/patient/home";
}
}
my choose-visit-form.jsp:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" isELIgnored="false"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib uri = "http://java.sun.com/jsp/jstl/core" prefix = "c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<table border="1">
<tr>
<td>ID:</td>
<td>Day:</td>
<td>Time:</td>
<td>Action</td>
</tr>
<c:forEach items="${visits}" var="visit">
<tr>
<td>${visit.id}</td>
<td>${visit.day}</td>
<td>${visit.time}</td>
<td><a href="saveVisit?visitId=${visit.id}"> Zapisz </a></td>
</tr>
</c:forEach>
</table>
</body>
</html>
patient-form.jsp:
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<div align="center">
<form:form action="savePatient?visitId=${visit.id}" modelAttribute="patient">
<table>
<tr>
<td>Imie: <form:input path="firstName"/></td>
</tr>
<tr>
<td>Nazwisko: <form:input path="lastName"/></td>
</tr>
<tr>
<td>Adres: <form:input path="address"/></td>
</tr>
<tr>
<td>Numer :<form:input path="number"/></td>
</tr>
<tr>
<td>
<input type="submit" value="Zapisz"/>
</td>
</tr>
</table>
</form:form>
</div>
</body>
</html>
my services:
@Service
@Transactional
public class PatientServiceImpl implements PatientService {
@Autowired
private PatientRepository repo;
@Override
public List<Patient> getPatients() {
return repo.findAll();
}
@Override
public Patient getPatient(Integer id) {
return repo.findById(id).get();
}
@Override
public void savePatient(Patient patient) {
repo.save(patient);
}
@Override
public void deletePatient(Integer id) {
repo.deleteById(id);
}
@Override
public List<Patient> search(String keyword) {
// TODO Auto-generated method stub
return null;
}
@Service
@Transactional
public class VisitServiceImpl implements VisitService{
@Autowired
private VisitRepo visitRepo;
@Override
public List<Visit> getVisits() {
return visitRepo.findAll();
}
@Override
public List<Visit> getVisitsFromDentist(Integer id) {
return visitRepo.findAllByDentistId(id);
}
@Override
public Visit getVisit(Integer id) {
return visitRepo.findById(id).get();
}
@Override
public void saveVisit(Visit visit) {
visitRepo.save(visit);
}
@Override
public void deleteVisit(Integer id) {
visitRepo.deleteById(id);
}
@Override
public List<Visit> search(String keyword) {
return null;
}
}