For some reason I can't delete an object that belongs to a many to many relationship. I get the following error:
Exception in thread "main" org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): [edu.cs157b.hibernate.AppointmentRequest#11]
at org.hibernate.internal.SessionImpl.forceFlush(SessionImpl.java:1232)
Here are my three classes that map the many to many relationship. Essentially, Doctor has many Patients through AppointmentRequest & vice versa. Here are the classes
Doctor
package edu.cs157b.hibernate;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
#Entity
#Table(name="DOCTOR_INFO")
#NamedQueries (
{
#NamedQuery(name = "Doctor.getAll", query = "from Doctor"),
#NamedQuery(name = "Doctor.findByName", query = "from Doctor where name = :name")
}
)
public class Doctor implements Person {
private int id;
private String name;
private Specialty specialty;
private List<AppointmentRequest> appointmentRequests = new ArrayList<AppointmentRequest>();
#Id
#GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Column(unique=true)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#ManyToOne (fetch = FetchType.EAGER, cascade= CascadeType.PERSIST)
#JoinColumn(name="specialty_id")
public Specialty getSpecialty() {
return specialty;
}
public void setSpecialty(Specialty specialty) {
this.specialty = specialty;
}
#OneToMany(mappedBy="doctor", targetEntity = AppointmentRequest.class,
fetch=FetchType.EAGER, orphanRemoval=true, cascade= CascadeType.ALL)
public List<AppointmentRequest> getAppointmentRequests() {
return this.appointmentRequests;
}
public void setAppointmentRequests(List<AppointmentRequest> appointmentRequests) {
this.appointmentRequests = appointmentRequests;
}
#Transient
public List<Patient> getPatients() {
List<Patient> patients = new ArrayList<Patient>();
for(AppointmentRequest appointment:appointmentRequests) {
patients.add(appointment.getPatient());
}
return patients;
}
}
Patient
package edu.cs157b.hibernate;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
#Entity
#Table(name="PATIENT_INFO")
#NamedQueries (
{
#NamedQuery(name = "Patient.getAll", query = "from Patient"),
#NamedQuery(name = "Patient.findByName", query = "from Patient where name = :name")
}
)
public class Patient implements Person {
private int id;
private String name;
private String medical_record;
private List<AppointmentRequest> appointmentRequests = new ArrayList<AppointmentRequest>();
public String getMedical_record() {
return medical_record;
}
public void setMedical_record(String medical_record) {
this.medical_record = medical_record;
}
#Id
#GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Column(unique=true)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#OneToMany(mappedBy="patient", targetEntity = AppointmentRequest.class,
fetch=FetchType.EAGER, orphanRemoval=true, cascade= CascadeType.ALL)
public List<AppointmentRequest> getAppointmentRequests() {
return this.appointmentRequests;
}
public void setAppointmentRequests(List<AppointmentRequest> appointmentRequests) {
this.appointmentRequests = appointmentRequests;
}
#Transient
public List<Doctor> getDoctors() {
List<Doctor> doctors = new ArrayList<Doctor>();
for(AppointmentRequest appointment:appointmentRequests) {
doctors.add(appointment.getDoctor());
}
return doctors;
}
}
ApppointmentRequest
package edu.cs157b.hibernate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.TimeZone;
import javax.persistence.*;
import org.hibernate.annotations.Type;
import java.util.List;
#Entity
#Table(name="APPOINTMENT_REQUEST")
#NamedQueries (
{
#NamedQuery(name = "AppointmentRequest.getAll", query = "from AppointmentRequest"),
#NamedQuery(name = "AppointmentRequest.findByDoctorId", query = "from AppointmentRequest where doctor_id = :doctor_id"),
#NamedQuery(name = "AppointmentRequest.findByPatientId", query = "from AppointmentRequest where patient_id = :patient_id"),
#NamedQuery(name = "AppointmentRequest.findByID", query = "from AppointmentRequest where id = :id")
}
)
public class AppointmentRequest {
private int id;
private Doctor doctor;
private Patient patient;
private boolean fulfilled = false;
private Calendar time;
private final SimpleDateFormat timestampFormat = new SimpleDateFormat("MM/dd/yyyy h a");
public Calendar getTime() {
return time;
}
#Transient
public String getFormattedTime() {
String result = timestampFormat.format(time.getTime());
return result;
}
public void setTime(Calendar time) {
this.time = time;
}
public boolean isFulfilled() {
return fulfilled;
}
public void setFulfilled(boolean fulfilled) {
this.fulfilled = fulfilled;
}
#Id
#GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#ManyToOne (fetch = FetchType.EAGER, cascade= CascadeType.PERSIST)
#JoinColumn(name="doctor_id")
public Doctor getDoctor() {
return doctor;
}
public void setDoctor(Doctor doctor) {
this.doctor = doctor;
}
#ManyToOne (fetch = FetchType.EAGER, cascade= CascadeType.PERSIST)
#JoinColumn(name="patient_id")
public Patient getPatient() {
return patient;
}
public void setPatient(Patient patient) {
this.patient = patient;
}
}
Doctor Delete Method
public void deleteDoctor(String doctor_name) {
Session session = sessionFactory.openSession();
Doctor doctor = new Doctor();
try {
session.beginTransaction();
Query query = session.getNamedQuery("Doctor.findByName");
query.setString("name", doctor_name);
doctor = (Doctor) query.uniqueResult();
if(doctor == null) {
throw new NullPointerException();
}
List<AppointmentRequest> appointments = doctor.getAppointmentRequests();
for(AppointmentRequest appointment:appointments) {
appointment.setDoctor(null);
}
session.delete(doctor);
session.getTransaction().commit();
}
finally {
session.close();
}
}
What this exception really means is you are telling Hibernate to remove object from database but at the same time this object still exist (that means still exist in java or database) in mapped collection via Persistent entity which has CascadeType.PERSIST annotated over it.
It's like having something tied through elastic rubber on the window and then poke it hoping it will drop. Hibernate is smart it is saving you from doing meaningless stuff, it tells you what to do
deleted object would be re-saved
by cascade (remove deleted object from associations)
Sine you are doing appointment.setDoctor(null); it will remove object from collection (only in java as you are not explicitly or implicitly updating appointment).You have CascadeType.PERSIST on doctor that means when hibernate is going to commit the transaction it will find that appointment has association to doctor you just deleted that means if you remove that doctor from table, hibernate has to go and create same doctor as you have not told him to make appropriate changes in appointment as he follows all the entity rules set by you. Since hibernate is smart he knows this and he will throw a exception for you saying don't be an oxymoron and do the right thing.
Now there are more than one solution that I can think of here
Use cascade={CascadeType.PERSIST,CascadeType.REMOVE} or cascade=CascadeType.ALL on getDoctor() in AppointmentRequest
As mentioned in hibernate document here
It doesn't usually make sense to enable cascade on a #ManyToOne or
#ManyToMany association. Cascade is often useful for #OneToOne and
#OneToMany associations.
remove cascade from getDoctor
Since you have FetchType.EAGER on getDoctor() with cascade specified it is little complicated for me interpret the behaviour of hibernate but in this questions they have solved by using FetchType.LAZY am not sure if it will work out for you.
You can do session.saveOrUpdate(appointment) on all the AppointmentRequest which has this doctor and then go for session.delete(doctor);
Hope you this would solve your problem.
Related
I would like to create a new Product with a category. If the category doesn't exist then also create the category. So far so good with this use case.
My second use case comes when I want to create another product with the same category. Since I have my Category entity with unique name then when I call my service it throws the duplicate error key. What I want is to be able to create the second product and update the category to have this product.
This is my Category Entity
package com.smolano.cupboard.entities;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
#Entity
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Category implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(unique = true)
private String name;
#ManyToMany(mappedBy = "categories", fetch = FetchType.LAZY)
private Set<Product> products = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Product> getProducts() {
return products;
}
public void setProducts(Set<Product> products) {
this.products = products;
}
}
This is my Product Entity
package com.smolano.cupboard.entities;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
#Entity
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Product implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinTable(
name = "product_categories",
joinColumns = {#JoinColumn(name = "product_id")},
inverseJoinColumns = {#JoinColumn(name = "category_id")}
)
private Set<Category> categories = new HashSet<>();
private String barCode;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Category> getCategories() {
return categories;
}
public void setCategories(Set<Category> categories) {
this.categories = categories;
}
public String getBarCode() {
return barCode;
}
public void setBarCode(String barCode) {
this.barCode = barCode;
}
}
My category repository
package com.smolano.cupboard.repositories;
import com.smolano.cupboard.entities.Category;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CategoryRepository extends JpaRepository<Category, Long> {
}
and my product repository
package com.smolano.cupboard.repositories;
import com.smolano.cupboard.entities.Product;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product, Long> {
}
Rest of my code can be found here
https://github.com/santfirax/backend-product-store-java
In this example, I don't see a necessity of having many to many relationship. one to many can serve the purpose, where one category can have multiple products and you can create multiple products using the same category which is unique by name.
If you still want to achieve it, you need to have a new table with the combination of primary keys of both tables and that is going to be the unique combination.
refer these pages for more info 1 and 2 with visual representation.
Try to avoid using CascadeType.REMOVE for many-to-many associations, since it may generate too many queries and remove more records than you expected. Here is an article that explains this behavior in details. Since you're using CascadeType.ALL in your mapping it also includes CascadeType.REMOVE.
Regarding adding/updating new categories to product entity. It would be helpful to override equals and hashCode methods. Since in your example Category.name should be unique and basically you distinguish categories by their names, then your implementations may look like this:
#Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Category))
return false;
Category other = (Category) o;
return (this.name == null && other.name == null) || (this.name != null && this.name.equals(other.name));
}
#Override
public int hashCode() {
return this.name.hashCode();
}
This way you'll make sure that your Product.categories field will not contain categories with the same name.
Assuming that your entity mapping have cascade = {CascadeType.PERSIST, CascadeType.MERGE}, your service class may look similar to following:
#Service
#Transactional
public class ProductService {
#Autowired
private ProductRepository productRepository;
public Product createProduct(Product product) {
return productRepository.save(product);
}
public Product saveCategoryInProduct(Long productId, Category category) {
return productRepository
.findById(productId)
.map(product -> addCategory(product, category))
.map(productRepository::save)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
}
private Product addCategory(Product product, Category category) {
product.getCategories().add(category);
return product;
}
}
By calling saveCategoryInProduct, you'll add new categories to the product entities. If Category entity contains id (not null) then new record will be created in product_categories table.
However if Category entity does not have id( is null), then there will be an attempt to create new record in category table first, then associate it to provided product id(by creating record in product_categories). In this case you may encounter DuplicateKeyException. To deal with it you may modify addCategory method in a following way:
private Product addCategory(Product product, Category category) {
product.getCategories().add(
categoryRepository
.findByName(category)
.orElse(category));
return product;
}
This way you'll make sure that the category you add either retrieved from db(therefore will not be created again) or does not exists yet.
I have Employee class and Qualification class , I added qualifications of a employee successfully. But ,When i try to update the particular employees qualification by adding one more qualification. I don't have a idea to do.Kindly suggest some view
Employee class
#Entity
#Table(name = "Tbl_Employee")
public class Employee {
private int empId;
private String empName;
private Employee_Address addressDetail;
private List<Employee_Qualification> qualifications;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="EmployeeId", updatable = false, nullable = false)
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
#Column(name="EmployeeName")
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
#OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinColumn(name="EmpAdd_FK")
public Employee_Address getAddressDetail() {
return addressDetail;
}
public void setAddressDetail(Employee_Address addressDetail) {
this.addressDetail = addressDetail;
}
#OneToMany(targetEntity=Employee_Qualification.class, mappedBy="employee"
,cascade=CascadeType.ALL, fetch=FetchType.LAZY)
public List<Employee_Qualification> getQualifications() {
return qualifications;
}
public void setQualifications(List<Employee_Qualification> qualifications) {
this.qualifications = qualifications;
}
}
Qualification class
#Entity
#Table (name="Tbl_Employee_Qualification")
public class Employee_Qualification {
private int qualificationId;
private String qualification;
private Employee employee;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="QualificationId", updatable = false, nullable = false)
public int getQualificationId() {
return qualificationId;
}
public void setQualificationId(int qualificationId) {
this.qualificationId = qualificationId;
}
#Column(name="Qualifications")
public String getQualification() {
return qualification;
}
public void setQualification(String qualification) {
this.qualification = qualification;
}
#ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinColumn(name="Emp_FK")
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}
Implementation class
// Update Employee and Employee_Qualification from Employee entity class [OnetoManny and ManytoOne bidirectional]
Employee emp =(Employee) session.createQuery("from Employee where empId='10'").uniqueResult();
Employee_Qualification newQ1 = new Employee_Qualification();
newQ1.setQualification("ECE");
List<Employee_Qualification> q1 = emp.getQualifications();
q1.add(newQ1);
emp.setQualifications(q1);
session.save(q1);
session.getTransaction().commit();
When you have a bidirectional relation you need to wire up both sides. In your example you already have this:
q1.add(newQ1);
but you also need to do the reverse binding too:
newQ1.setEmployee(emp)
Just a note : You have Cascade.ALL to both relations (oneToMany and ManyToOne) between your employee and qualification. I haven' t run your code but i am pretty sure is going to create an issue.
You have to decide which entity is responsible to update the other. (i,e if you choose to save the qualifications and the changes to be propagated to employee then remove the cascade from the #oneToMany in the Employee class
I read https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/.
I tried suggestion config like(using spring data JPA,hibernate 5.0 as vendor ):
public class PaperSubjectType{
#Id
private Long id;
#OneToOne(fetch = FetchType.LAZY)
#MapsId
private PaperSetting paperSetting;
..
}
class PaperSetting{
#Id
#GeneratedValue
private Long id;
..
}
first I tried the example:
PaperSetting paperSettingInDb = paperSettingRepository.findOne(1);
PaperSubjectType paperSubjectType = new PaperSubjectType();
paperSubjectType.setSubjectCode("91");
paperSubjectType.setPaperSetting(paperSettingInDb);
paperSubjectTypeRepository.save(paperSubjectType);
error:detached entity passed to persist:PaperSetting.
it seems hibernate take PaperSetting as detached when cascade
2 if I want to create both PaperSubjectType and PaperSetting together,do I need to do this:
PaperSetting paperSetting = new PaperSetting();
paperSetting.setxx;
PaperSetting paperSettingInDbNew = paperSettingRepository.save(paperSetting);
PaperSubjectType paperSubjectType = new PaperSubjectType();
paperSubjectType.setPaperSetting(paperSettingInDbNew);
paperSubjectTypeRepository.save(paperSubjectType);
or I should use bidirectional in this situation?
thank you!
I think you may have forgotten to wrap the logic in a #Transactional block
#Transactional
PaperSetting paperSettingInDb = paperSettingRepository.findOne(1);
PaperSubjectType paperSubjectType = new PaperSubjectType();
paperSubjectType.setSubjectCode("91");
paperSubjectType.setPaperSetting(paperSettingInDb);
paperSubjectTypeRepository.save(paperSubjectType);
without that crudRepository.findOne() will open it's own short lived transaction so when you get the return of findOne() the entity is already detached, hence the error
I tried it Hibernate 5.2 and it works like a charm.
Assuming you have these entities:
#Entity(name = "Person")
public static class Person {
#Id
#GeneratedValue
private Long id;
#NaturalId
private String registrationNumber;
public Person() {}
public Person(String registrationNumber) {
this.registrationNumber = registrationNumber;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRegistrationNumber() {
return registrationNumber;
}
}
#Entity(name = "PersonDetails")
public static class PersonDetails {
#Id
private Long id;
private String nickName;
#OneToOne
#MapsId
private Person person;
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
And this data access logic:
Person _person = doInJPA( this::entityManagerFactory, entityManager -> {
Person person = new Person( "ABC-123" );
entityManager.persist( person );
return person;
} );
doInJPA( this::entityManagerFactory, entityManager -> {
Person person = entityManager.find( Person.class, _person.getId() );
PersonDetails personDetails = new PersonDetails();
personDetails.setNickName( "John Doe" );
personDetails.setPerson( person );
entityManager.persist( personDetails );
} );
The test passes just fine in Hibernate ORM.
Maybe it was a bug in 5.0 that got fixed, so you are better of upgrading.
1) Add cascading option:
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#MapsId
private PaperSetting paperSetting;
2) Having that in place, you can save only PaperSubjectType while creating both entities anew:
PaperSetting paperSetting = new PaperSetting();
paperSetting.setxx;
PaperSubjectType paperSubjectType = new PaperSubjectType();
paperSubjectType.setPaperSetting(paperSettingInDbNew);
paperSubjectTypeRepository.save(paperSubjectType);
I have 2 classes (BusinessAccount and Projects (shown below) that are mapped to a MySql database) where a 1:M relationship exists between BusinessAccounts and Projects. I am successfully inserting data to the database but am having a problem when it comes to querying the database. The problem that I am having is that I have no getter or setter for the foreign key, 'contractor_id' in the Projects class. The query that I want to carry out is to return the list of the names of all projects for a given BusinessAccount, by searching by the foreign key reference in the Projects table. I can do this no problem in mySQL but as there is no reference to the contractor_id as a java entity in the Projects class, I'm not sure how to do this search from within my java class. (Note: I tried to declare the foreign key along with getters and setters in the Projects class but as I have these mapped by the 1:Many relationship in the class already, it wouldn't compile as they were flagged as duplicate entities.) I'm sure it's something obvious that I'm missing but any help is much appreciated!
public List<Projects> getProjectList() {
factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
EntityManager em = factory.createEntityManager();
List<Projects> projectList = new ArrayList<Projects>();
em.getTransaction().begin();
String sessionEmail=Util.getEmail();
Query myQuery = em.createQuery("SELECT u FROM BusinessAccount u WHERE u.email=:email");
myQuery.setParameter("email", sessionEmail);
List<BusinessAccount> userList=myQuery.getResultList();
BusinessAccount account =userList.get(0);
Query myQuery2 = em.createQuery("SELECT distinct p.* FROM BusinessAccount u "
+ "INNER JOIN Projects p ON p.contractor_id=:userID");
/*Note p.contractor_id above refers to the entity in the
mysql database (and won't work obviously), I want to refer
to it's java equivalent but am not sure how to do that*/
myQuery2.setParameter("userID", account.getId());
projectList=myQuery2.getResultList();
em.getTransaction().commit();
em.close();
return projectList;
}
#Entity
#Table(name = "business_accounts")
public class BusinessAccount {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "first_name")
private String firstName;
#Column(name = "surname")
private String surname;
#OneToMany(mappedBy = "businessAccount", fetch = FetchType.EAGER, cascade = { CascadeType.ALL })
private List<Projects> projects;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getSurname() {
return surname;
}
public List<Projects> getProjects()
{
if (projects == null)
{
projects = new ArrayList<Projects>();
}
return projects;
}
public void setProjects(List<Projects> projects)
{
this.projects = projects;
}
}
#Entity
#Table(name = "projects")
public class Projects {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int project_id;
#Column(name = "project_name")
private String projectName;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({ #JoinColumn(name = "contractor_id", referencedColumnName="id") })
private BusinessAccount businessAccount;
public BusinessAccount getBusinessAccount() {
if (businessAccount == null) {
businessAccount = new BusinessAccount();
}
return businessAccount;
}
public void setBusinessAccount(BusinessAccount businessAccount) {
this.businessAccount = businessAccount;
}
public int getProject_id() {
return project_id;
}
public void setProject_id(int project_id) {
this.project_id = project_id;
}
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
}
The JPA query would be something like (you need to use the relation property, but no need for the foreign key itself - please try, it may need some tweaking):
SELECT p FROM BusinessAccount u, IN(u.projects) p WHERE u.id=:userId
But do you really need the query? You can get the related projects from the property:
BusinessAccount account = ...
List<Projects> projectList = account.getProjects();
Try this:
Query myQuery2 = em.createQuery("SELECT distinct p.* FROM BusinessAccount u "
+ "INNER JOIN Projects p ON p.businessAccount=:businessAccount");
myQuery2.setParameter("businessAccount", account);
I have a relationship between Student entity and Publication as One to Many. I need to delete publication from sutdent. When I try to delete publication object but always get the exception:
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [org.irs.entities.GroupStudent#1]
I do not know why it happens. I use Spring MVC 3.2 and Hibernate.
Student entity
#Entity
#org.hibernate.annotations.DynamicUpdate(value = true)
#Table(name = "Student")
public class Student implements Serializable {
public Student() {}
public Student(String studentFullName, String studentBook,
int studentEnter, String studentOKR) {
this.studentFullName = studentFullName;
this.studentBook = studentBook;
this.studentEnter =studentEnter;
this.studentOKR = studentOKR;
}
// create connectivity with table GroupStudent
private GroupStudent groupStudent;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "GroupStudentId")
public GroupStudent getGroupStudent() {
return this.groupStudent;
}
public void setGroupStudent(GroupStudent groupStudent) {
this.groupStudent = groupStudent;
}
// create connectivity with table Publication
private Set<Publication> publications = new HashSet<Publication>();
#OneToMany(mappedBy = "student", cascade = CascadeType.ALL, orphanRemoval = true)
public Set<Publication> getPublications() {
return publications;
}
public void setPublications(Set<Publication> publications) {
this.publications = publications;
}
// other methods
}
Pulication entity
#Entity
#Table(name = "Publication")
public class Publication implements Serializable {
public Publication() {}
public Publication(String publicationTitle, String publicationType,
String publicationPlace, Date publicationDate) {
this.publicationTitle = publicationTitle;
this.publicationType = publicationType;
this.publicationPlace = publicationPlace;
this.publicationDate = publicationDate;
}
// create connectivity with table Student
private Student student;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "StudentId")
public Student getStudent() {
return this.student;
}
public void setStudent(Student student) {
this.student = student;
}
}
GroupStudent entity
#Entity
#Table(name = "GroupStudent")
public class GroupStudent implements Serializable {
public GroupStudent() {}
public GroupStudent(String groupStudentNumber) {
this.groupStudentNumber = groupStudentNumber;
}
// create connectivity with table Student
private Set<Student> students = new HashSet<Student>();
#OneToMany(mappedBy = "groupStudent", cascade = CascadeType.ALL, orphanRemoval = true)
public Set<Student> getStudents() {
return this.students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
Controller
#RequestMapping(value = "/deletePublication.html", method = RequestMethod.GET)
public ModelAndView deletePublication(#RequestParam("studentId") Long studentId) {
....
ps.deletePublication(ps.selectPublicationsById(2L));
....
return modelandview;
}
This error happens when you try to fetch entity that was already in the hibernate context. You can't have two attached entities at the same time.
In your controller you firts call ps.selectPublicationsById(2L), that probably causes the error.
Try to replace the delete logicc with HQL or native SQL delete.
String hql = "delete from Publication where Id= :id";
session.createQuery(hql).setString("id", id).executeUpdate();