I have two mapped types, related many-to-many.
#Entity
#Table(name = "students")
public class Student{
...
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
name = "students2courses",
joinColumns = { #JoinColumn(
name = "student_id",
referencedColumnName = "_id") },
inverseJoinColumns = { #JoinColumn(
name = "course_id",
referencedColumnName = "_id") })
public Set<Course> getCourses() {
return courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
}
...
}
__
#Entity
#Table(name = "courses")
public class Course{
...
#ManyToMany(fetch = FetchType.EAGER, mappedBy = "courses")
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
...
}
But if I update/delete Course entity, records are not created/deleted in table students2courses. (with Student entity updating/deleting goes as expected)
I wrote abstract class HibObject
public abstract class HibObject {
public String getRemoveMTMQuery() {
return null;
}
}
which is inherited by Student and Course.
In DAO I added this code (for delete() method):
String query = obj.getRemoveMTMQuery();
if (query != null) {
session.createSQLQuery(query).executeUpdate();
}
and I ovrerided method getRemoveMTMQuery() for Course
#Override
#Transient
public String getRemoveMTMQuery() {
return "delete from students2courses where course_id = " + id + ";";
}
Now it works but I think it's a bad code.
Is there a best way to solve this problem?
Related
So I have two entities with a bi-directional #ManyToMany relation - Student and Course.
My Student class being:
#Entity
#Table(name = "student")
public class Student {
#Id
#GeneratedValue
private int id;
#Column(name = "role", unique = true, nullable = false)
private String studentName;
#ManyToMany
#JoinTable(name = "student_course",
joinColumns = {#JoinColumn(name = "student_id",
referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "course_id",
referencedColumnName =
"id")})
private Set<Course> course = new HashSet<>();
public String getStudentName() {
return studentName;
}
public void setStudentName(final String studentName) {
this.studentName = studentName;
}
public Set<Course> getCourses() {
return courses;
}
public void setCourses(final Set<Course> courses) {
this.courses = courses;
}
#Override
public int hashCode() {
...
}
#Override
public boolean equals(final Object obj) {
...
}
#Override
public String toString() {
...
}
My Course class being:
#Entity
#Table(name = "course")
public class Course {
#Id
#GeneratedValue
private int id;
#Column(name = "course", nullable = false, unique = true)
private String course;
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "courses")
private Set<Student> students = new HashSet<>();
public String getCourse() {
return course;
}
public void setCourse(final String course) {
this.course = course;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(final Set<Student> students) {
this.students = students;
}
#Override
public int hashCode() {
...
}
#Override
public boolean equals(final Object obj) {
...
}
#Override
public String toString() {
...
}
Using the hibernate entitymanager I want to persist both the entities. So in my DbInitializer(), I have something like this that fills data for the Course entity.
private Set<Course> initCourses() {
final Set<Course> courses =
CourseProvider.getTestCourses();
for (final Course course : courses) {
entityManager.persist(course);
}
return courses;
}
This works fine. But when I try to fill data for the Student entity, it asks me save the transient instance before flushing.
private List<Student> initStudents() {
final Set<Student> students = StudentProvider.getTestStudents();
for (final Student student : students) {
entityManager.persist(student);
}
return students;
}
StudentProvider class:
public class StudentProvider {
public static List<Student> getTestStudentsList() {
final List<Student> students =
StudentFactory.createStudents();
return students;
}
}
StudentFactory class:
public class StudentFactory {
public static final List<Student> createStudents() {
final EnumSet<StudentEnum> students =
EnumSet.allOf(StudentEnum.class);
final List<Student> studentList = new ArrayList<>();
for (final StudentEnum s : students) {
final Student student = new Student();
student.setStudentName(s.toString());
student.setCourses(s.transform());
studentList.add(student);
}
return studentList;
}
The StudentProvider calls the StudentFactory that sets values for Student.
The StudentEnum has a list of students with the corresponding courses.
I am aware that cascade = CascadeType.ALL could solve the problem. I tried using it but, it gives me a "Duplicate Entry error for the Course entity". And if I don't use the cascade it asks me to save the transient instance.
Could someone please suggest me a way without using cascasde???
I understand that I have to save the Course entity before persisting the Student entity.
I went through a couple of Stackoverflow questions but I couldn't solve the problem. Help needed!
Thank you in advance! :)
I have two connected classes,
Patient:
...
#Entity
#Table(schema="public",name="patient")
public class Patient{
..
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "patient_id")
public Integer getId() {
return Id;
}
public void setId(Integer id) {
Id = id;
}
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "patient_examination", catalog = "ALTAdb", joinColumns = {
#JoinColumn(name = "patient_id", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "examination_id",nullable = false, updatable = false) })
public Set<Examination> getExaminations() {
return examinations;
}
public void setExaminations(Set<Examination> examinations) {
this.examinations = examinations;
}
...
Examination:
...
#Entity
#Table(schema="public",name="examination")
public class Examination{
..
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "examination_id")
public Integer getId() {
return Id;
}
public void setId(Integer id) {
Id = id;
}
#ManyToMany(fetch = FetchType.EAGER, mappedBy = "examinations")
public Set<Patient> getPatients() {
return patients;
}
public void setPatients(Set<Patient> patients) {
this.patients = patients;
}
...
And when I try to delete a record that is present olso in patient_examination
Code:
public boolean deleteExamination(int ExaminationId){
boolean deleted=false;
Session session=factory.getCurrentSession();
session.beginTransaction();
Query query =session.createQuery("select m from "+ Examination.class.getName() +" m");
List<Examination> examinations= query.getResultList();
for(Examination e: examinations){
if(e.getId()==ExaminationId){
session.delete(e);
deleted=true;
break;
}
}
session.getTransaction().commit();
return deleted;
}
this is my console:
"Examination" violates the external key constraint "fkexas9b9fwxn0t37wl60a4jcd3" on the table "patient_examination"
Detail: The key (examination_id) = (4) is still referenced by the table "patient_examination"
I do not know how to fix it.
I also tried to make a query to directly access to patient_examination, but I do not know a working method for it
Try #ManyToMany with CascadeType.REMOVE it will work as far as I know...
I have three classes, Site, GoupIP and IP
A Site has one or many GrouIPs.
A GroupIP has one or many IPs.
Here is the code:
Site
#Entity
#Table(name = "site")
public class Site implements Serializable {
private Set<GroupIp> groups;
#OneToMany(mappedBy = "site", fetch = FetchType.EAGER, cascade =CascadeType.ALL)
public Set<GroupIp> getGroups() {
return groups;
}
public void setGroups(Set<GroupIp> groups) {
this.groups = groups;
}
}
GroupIP
#Entity
#Table(name = "groupip")
public class GroupIp implements Serializable {
private Set<Ip> ips;
private Site site;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "site_id")
public Site getSite() {
return site;
}
#OneToMany(mappedBy = "groupip", fetch = FetchType.EAGER, cascade =CascadeType.ALL)
public Set<Ip> getIps() {
return ips;
}
public void setIps(Set<Ip> ips) {
this.ips= ips;
}
}
IP
#Entity
#Table(name = "ip")
public class Ip implements Serializable {
private GroupIp groupIp;
#ManyToOne(targetEntity = GroupIp.class,cascade = CascadeType.MERGE)
#JoinColumn(name = "groupip_id", nullable=false)
public GroupIp getGroupIp() {
return groupIp;
}
public void setGroupIp(GroupIp groupIp) {
this.groupIp = groupIp;
}
}
On GroupIp class, I m getting:
In attribute 'ips', the "mapped by" value 'groupip' cannot be resolved to an attribute on the target entity.
Whats wrong on my code ??
The mappedBy name that you have to put in the relationship is the name of the class attribute, not the table name.
So put #OneToMany(mappedBy = "groupIp",... (note the uppercase) instead of #OneToMany(mappedBy = "groupip",...
I have three tables: users(id, name, login, password), roles(id, name), user_roles(id, user_id, role_id)
This is my code
#Entity
#Table(name = "users")
public class User extends Model {
#Id
public Long id;
public String name;
public String login;
public String password;
#ManyToMany
#JoinTable(
name = "user_roles",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "role_id", referencedColumnName = "id")
)
public Set<Role> roles;
public static Finder<Integer, User> find = new Finder<>(User.class);
}
#Entity
#Table(name = "roles")
public class Role extends Model {
#Id
public Long id;
public String name;
#ManyToMany(mappedBy = "roles")
public List<User> users;
public static Finder<Integer, Role> find = new Finder<>(Role.class);
}
I want to display all users with roles, example: {"id":1, "name":"My Name", "login":"My Login", "password":"My Password", roles: [{"name":"ADMIN"}, {"name":"USER"}]}
How can I do this? I'm new in Ebean and ORM. Thanks for any help.
Update
public Result all() {
List<User> users = User.find.all();
return ok(toJson(users));
}
But now I getting stackoverflow error infinite recursion.
Make users.role = null and then return Json
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();