SOLVED
But the real problem wasn't hibernate, it was mainly me and second Netbeans.
I was making a post, and saving my data. But I was making a duplicate post in js, and Netbeans won't fire breakpoints twice (and I don't really know why). So, for me, it was making one post and just one insert. But no, two posts, and two inserts.
Sorry for losing your time :/
I'm new to Hibernate, so I'm having some problems, maybe it's just a silly one, I don't really know.
I'm trying to insert an object to database with a #ManyToOne relationship, but Hibernate is duplicating it when I persist and commit the transaction. This is my code.
User Post Class
#Entity
#Table(name = "USERPOST", schema = "ADMIN1")
public class UserPost implements java.io.Serializable {
private int iduserpost;
private String detail;
private User user;
public UserPost() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "IDUSERPOST", unique = true, nullable = false)
public int getIduserpost() {
return this.iduserpost;
}
public void setIduserpost(int iduserpost) {
this.iduserpost = iduserpost;
}
#Column(name = "DETAIL", nullable = false)
public String getDetail() {
return this.detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
#ManyToOne
#JoinColumn(name = "IDUSER")
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
User Class
#Entity
#Table(name = "USER", schema = "ADMIN1")
public class User implements java.io.Serializable {
private int iduser;
private String name;
private String email;
private Set<UserPost> posts;
public User() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "IDUSER", unique = true, nullable = false)
public int getIduser() {
return this.iduser;
}
public void setIduser(int iduser) {
this.iduser = iduser;
}
#Column(name = "NAME", nullable = false)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
#Column(name = "EMAIL", nullable = false)
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
#OneToMany(mappedBy = "user")
public Set<UserPost> getPosts() {
return posts;
}
public void setPosts(Set<UserPost> posts) {
this.posts = posts;
}
}
Insert Method on Manager
public void Insert(Object data) {
Session session = null;
try {
session = hibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
session.persist(data);
session.getTransaction().commit();
} catch (Exception e) {
System.err.println(e.getMessage());
throw e;
} finally {
if (session.isOpen()) {
session.close();
}
}
}
Insert on Servlet
FeedManager manager = new FeedManager();
UserPost post = new UserPost();
post.setDetail(text);
User usrPesist = (User) manager.GetById(User.class, idUser);
post.setUser(usrPesist);
manager.Insert(post);
The result I'm getting is TWO UserPosts being inserted to database, when what I want is just one.
Is there something wrong?
Since you have defined as private Set<UserPost> posts; in User Class,
implement equals and hashcode methods in UserPost class , in that way you ensure that since it is a Set it wont add duplicates
But this is not a optimal way though.
I think this is problem with you id generation strategy in your user class. Just try by setting id manually in user class object it will work.
Try changing your code with this :
#org.hibernate.annotations.Cascade( {org.hibernate.annotations.CascadeType.SAVE_UPDATE})
#OneToMany(mappedBy = "user")
#JoinColumn(name = "IDUSER")
public Set<UserPost> getPosts() {
return posts;
}
Related
I'm very new to Java Spring and have a little Problem.
I wan't to send the employee_id (from employees entity) to assignment entity in the body part (in Postman). Currently it's working, because I'm sending the employee_id as a PathVariable and I'm sending the assignment data with ResponseBody.
#PostMapping("/add/{employee_id}")
public void addEmployee(#PathVariable(value = "employee_id", required = false) Long employee_id,
#RequestBody Assignment a) {
Employee employeeById = employeeRepository.findById(employee_id)
.orElseThrow(() -> new RuntimeException("Employee not found"));
a.setEmployee(employeeById);
assignmentRepository.addAssignment(a);
}
It is working with the url localhost:8080/add/35. 35 is the employee_id and the assignment data can be send in the Body (of Postman). What I want to do is, to send the employee_id in the body too (so the url should only be /add), but I could not get it to work.
Like that:
{
"employee_id": 35,
"title": "abc"
}
Edited:
Assignment.java
public class Assignment {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToOne(optional = false)
#JoinColumn(name = "employee_id", nullable = false)
private Employee employee;
#Size(min = 3, max = 50)
private String assignment_title;
public Assignment() {
}
public Assignment(String assignment_title) {
super();
this.assignment_title = assignment_title;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAssignment_title() {
return assignment_title;
}
public void setAssignment_title(String assignment_title) {
this.assignment_title = assignment_title;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}
AssignmentService.java
public void addAssignment(Assignment e) {
AssignmentRepository.save(e);
}
AssignmentRepository.java
public interface AssignmentRepository extends CrudRepository<Assignment, Integer>{
}
Employee.java
public class Employee{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToOne(optional = false)
#JoinColumn(name = "user_id", nullable = false)
private User user;
#Size(min=3, max = 100)
private String title;
#Size(min=3, max = 50)
private String staff;
private Long degree;
public Employee() {}
public Employee( String title, String staff, Long degree) {
super();
this.title = title;
this.staff = staff;
this.degree = degree;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getStaff() {
return staff;
}
public void setStaff(String staff) {
this.staff = staff;
}
public Long getDegree() {
return degree;
}
public void setDegree(Long degree) {
this.degree = degree;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
EmployeeRepository.java
public interface EmployeeRepository extends CrudRepository<Employee, Integer>{
Optional<Employee> findById(Long id);
}
Thanks for your help in advance!
You need to ensure your body type Assignment has such property like
public class Assignment {
public Long employee_id;
// ommitted
}
And get it in your method like
#PostMapping("/add")
public void addEmployee(#PathVariable(value = "employee_id", required = false) Long employee_id, #RequestBody Assignment a) {
Long employee_id = a.employee_id;
Employee employeeById = employeeRepository.findById(employee_id)
.orElseThrow(() -> new RuntimeException("Employee not found"));
a.setEmployee(employeeById);
assignmentRepository.addAssignment(a);
}
But such implementation does not respect HTTP standards.
Please consider that your actual implementation almost respect those standards and you should rename your API this way : POST URL/v1/employees/{employee_id}
This blog explains those standards
EDIT with provided specifications:
#PostMapping(values = {"/v1/employees", "/v1/employees/{employee_id}"})
public void addEmployee(#PathVariable(value = "employee_id", required = false) Long employee_id, #RequestBody Assignment a) {
Long yourId = employee_id != null ? employee_id : a.employee_id;
if (yourId == null) {
throw new RuntimeException("No id given"); // Not clean either but implemented by OP
} else {
Employee employeeById = employeeRepository.findById(yourId)
.orElseThrow(() -> new RuntimeException("Employee not found"));
a.setEmployee(employeeById);
assignmentRepository.addAssignment(a);
}
}
As the pathvariable is optionnal you try to get it first from url and then from your body object.
EDIT 2 : An Assignment might be created with no Employee_id
First case : You accept that an Assignment might have no Employee.
Simply change your relation from Assignment to Employee :
#OneToOne(optional = true)
#JoinColumn(name = "employee_id", nullable = true)
private Employee employee;
Second case : You want to create a new Employee first and then bind it to your assignement as an Assignment should always have an Employee
#PostMapping(values = {"/v1/employees", "/v1/employees/{employee_id}"})
public void addEmployee(#PathVariable(value = "employee_id", required = false) Long employee_id, #RequestBody Assignment a) {
Long yourId = employee_id != null ? employee_id : a.employee_id;
Employee employeeById = yourId != null ?
employeeRepository.findById(yourId).orElseThrow(() -> new RuntimeException("Employee not found"))
: new Employee("title","staff",2L);
a.setEmployee(employeeById);
assignmentRepository.addAssignment(a);
}
I'm trying to map 2 entities (Course and Student), I have 2 Java classes and 2 MySQL tables, having a ManyToMany relationship. I created the junction table and java class Enrolment (as I want extra information such as the date of enrolment of a student to a course).
I'm trying to insert data using hibernate in this Enrolments table in the MySQL but I keep getting errors. Here are my POJO classes:
Course class:
#Entity
#Table(name = "course")
public class Course {
private int id;
#Column(name = "chapter_id")
private int chapterId;;
#Column(name = "name")
private String title;
#Column(name = "teacher_user_id")
private int teacherId;
#OneToMany(targetEntity=Enrolment.class, mappedBy="course", fetch=FetchType.LAZY)
// #JoinTable(name = "enrolment",
// joinColumns = #JoinColumn(name = "course_id"),
// inverseJoinColumns = #JoinColumn(name = "student_user_id"))
private List<Enrolment> enrolments = new ArrayList<Enrolment>();
public Course(){}
public Course(int id, int chapterId, String title, int teacherId) {
super();
this.id = id;
this.chapterId = chapterId;
this.title = title;
this.teacherId = teacherId;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getChapterId() {
return chapterId;
}
public void setChapterId(int chapterId) {
this.chapterId = chapterId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getTeacherId() {
return teacherId;
}
public void setTeacherId(int teacherId) {
this.teacherId = teacherId;
}
#OneToMany(mappedBy = "course")
public List<Enrolment> getEnrolments() {
return enrolments;
}
public void setEnrolments(List<Enrolment> courses) {
this.enrolments = courses;
}
public void addEnrolment(Enrolment enrolment) {
this.enrolments.add(enrolment);
}
}
Student class (this class is inherited from User parent class, I will attach User Class down below as well. In the database there are different tables as well: User and then Student and Teacher that inherit User parent entity):
#Entity
#Table(name = "student")
#PrimaryKeyJoinColumn(name = "user_id")
#OnDelete(action = OnDeleteAction.CASCADE)
public class Student extends User {
private int grade;
private List<Enrolment> enrolments = new ArrayList<Enrolment>();
public Student(){}
public Student(String fname, String lname, String email, String password, String address, String phone,
int userType, int grade, boolean isAdmin)
{
super(fname, lname, email, password, address, phone, userType, isAdmin);
this.grade=grade;
}
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
public void setEnrolments(List<Enrolment> courses) {
this.enrolments = courses;
}
#OneToMany(mappedBy = "student")
public List<Enrolment> getEnrolments() {
return enrolments;
}
public void addCourse(Enrolment course) {
this.enrolments.add(course);
}
public void addEnrolment(Enrolment enrolment) {
this.enrolments.add(enrolment);
}
}
User Class:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String firstname;
private String lastname;
private String email;
private String password;
private String address;
private String phone;
#Column(name = "user_type_id")
private int userType;
#Column(name = "is_admin")
private boolean isAdmin;
public User(String fname, String lname, String email, String password, String address, String phone,
int userType, boolean isAdmin) {
//super();
this.firstname = fname;
this.lastname = lname;
this.email = email;
this.password = password;
this.address = address;
this.phone = phone;
this.userType = userType;
this.isAdmin = isAdmin;
}
public User() {}
//getters & setters
And finally this is the Enrolment class:
#Entity
#Table(name = "enrolment")
public class Enrolment {
private int id;
private Student user;
private Course course;
#Column(name = "enrolment_date")
private Date enrolmentDate;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "student_user_id")
public User getUser() {
return user;
}
public void setUser(Student user) {
this.user = user;
}
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "course_id")
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
public Date getEnrolmentDate() {
return enrolmentDate;
}
public void setEnrolmentDate(Date enrolmentDate) {
this.enrolmentDate = enrolmentDate;
}
So I'm trying to read a course and a student from database and insert the information in this Enrolment table but it gives errors since trying to read a Course. Here is the DAO method:
#SuppressWarnings("deprecation")
#Transactional
public List<Course> getCoursesOfChapter(int chapterId) {
Configuration con = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Course.class);
SessionFactory sf = con.buildSessionFactory();
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
Query query = session.createQuery("from Course where chapter_id = :chapterId");
query.setParameter("chapterId",chapterId);
// List list = query.list();
tx.commit();
return (List<Course>) query.list();
It throws the error at the session factory building:
Exception in thread "main" org.hibernate.AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class: models.Course.enrolments[models.Enrolment]
at org.hibernate.cfg.annotations.CollectionBinder.bindManyToManySecondPass(CollectionBinder.java:1255)
at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:808)
at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:733)
at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:54)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1696)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1664)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:287)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:84)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:474)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:85)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:689)
at dao.CourseDAO.getCourse(CourseDAO.java:52)
at webapp.Main.main(Main.java:132)
Finally, this is my call:
CourseDAO cdao = new CourseDAO();
Course course = cdao.getCourse(1);
I've tried playing with the annotations, make them ManyToMany instead of ManyToOne. I tried to map the User class instead of Student but still didn't work. I tried to make it without the junction class of Enrolment and just generate it without having an actual class for it but still didn't work (as I had to work with 2 session.save() methods one after the other which also gave some error that I couldn't solve). Probably it's a small thing that I'm missing here but I just can't figure it out, sorry for too long code but I really need to solve it fast. If you read through here, I really thank you!
So my question is: Am I missing something here from these mappings and annotations or I should change the structure of my classes?
Boiling down a problem to the bare minimum greatly helps others help you. Here are simpler versions of your student, course and enrollment classes that can be unit tested easily. The many-to-many association between course and student is separated into two many-to-one associations from Enrollment. Note that the associations are bidirectional and that the many side is mapped by the one side. Student cascades persistence operations to Enrollment, which reflects how schools normally work: students enroll in courses, not the other way around.
Course.java
#Entity
public class Course {
#Id
#GeneratedValue
private Long id;
private String title;
#OneToMany(mappedBy = "course")
private List<Enrollment> enrollments;
Course() {
}
Course(String title) {
this.title = title;
this.enrollments = new ArrayList<>();
}
void add(Enrollment enrollment) {
enrollments.add(enrollment);
}
Long getId() {
return id;
}
List<Enrollment> getEnrollments() {
return enrollments;
}
}
Student.java
#Entity
public class Student {
#Id
#GeneratedValue
private Long id;
private String name;
#OneToMany(mappedBy = "student", cascade = ALL, orphanRemoval = true)
private List<Enrollment> enrollments;
Student() {
}
Student(String name) {
this.name = name;
this.enrollments = new ArrayList<>();
}
void enroll(Course course) {
enrollments.add(new Enrollment(course, this));
}
}
Enrollment.java
#Entity
public class Enrollment {
#Id
#GeneratedValue
private Long id;
#ManyToOne
private Course course;
#ManyToOne
private Student student;
Enrollment() {
}
Enrollment(Course course, Student student) {
this.course = course;
this.student = student;
course.add(this);
}
}
The test case below checks that the entities are mapped and associated correctly. You can run it with Spring Boot.
SchoolTest.java
#RunWith(SpringRunner.class)
#SpringBootTest
#Transactional
public class SchoolTest {
#Autowired
private CourseRepository courseRepository;
#Autowired
private StudentRepository studentRepository;
#Test
public void run() {
Course course = courseRepository.save(new Course("cs_101"));
int studentCount = 3;
for (int i = 1; i <= studentCount; i++) {
Student student = new Student("student_" + i);
student.enroll(course);
studentRepository.save(student);
}
// push changes to the database and clear the existing entities
// to make the subsequent operations load from the database
entityManager.flush();
entityManager.clear();
Optional<Course> savedCourse = courseRepository.findById(course.getId());
assertTrue(savedCourse.isPresent());
assertEquals(studentCount, savedCourse.get().getEnrollments().size());
}
}
As the warning said, your Enrollment is not registered in Hibernate. If you really don't need it. Please use transient annotation. read more here
I have created a simple program that will ask the user for their username and everything was working correctly until the point of the authentication. I have manually inserted data into the database for testing purposes and now I want to authenticate the login of a user by checking if they have entered the corresponding username as the same one on the database. However, I am being returned a null value when I ask for the getters of the administrator object.
Can someone please help me on why null is being returned whilst data is in the database? Thank you.
For reference purposes:
public void actionPerformed(ActionEvent e) {
//objects for connection
//Testing
Administrator cevo = new Administrator();
//==========================================//
Session session = HibernateUtility.getSessionFactory().openSession();
session.beginTransaction();
if (username.getText().equals(cevo.getGivenName())) { //Returned Value is Null, but data is present in DB.
System.out.println("MATCH");
}
else{
System.out.println(cevo.getGivenName());
System.out.println(username.getText());
System.out.println("NO MATCH");
}
session.clear();
session.close();
}
});
}
This is my Administrator class, for reference purposes:
#Entity()
#Table(name = "ADMINISTRATOR", schema = "registrationsystem")
public class Administrator implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
#JoinColumn(name ="ID", nullable = false)
protected int ID;
#Column(name = "NAME")
protected String name;
#JoinColumn(name = "FAMILYNAME")
//#OneToOne(mappedBy = "familyname", fetch = FetchType.LAZY)
protected String familyName;
#JoinColumn(name = "AGE")
//#OneToOne(mappedBy = "age", fetch = FetchType.LAZY)
protected int age;
#JoinColumn(name = "OCCUPATION")
// #OneToOne(mappedBy = "occupation", fetch = FetchType.LAZY)
protected Occupation occupation;
public Administrator() {
}
public String getGivenName() {
return name;
}
public void setGivenName(String givenName) {
this.name = givenName;
}
public String getFamilyName() {
return familyName;
}
public void setFamilyName(String familyName) {
this.familyName = familyName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Occupation getOccupation() {
return occupation;
}
public void setOccupation(Occupation occupation) {
this.occupation = occupation;
}
public int getID() {
return ID;
}
public void setID(int ID) {
this.ID = ID;
}
Your code seems to be a bit confusing, since you dont actually query for anything in the database.
Administrator cevo = new Administrator();
if (username.getText().equals(cevo.getGivenName())) {
System.out.println("MATCH");
}
It is obvious that cevo.getGivenName() is returning null, since it does not have been initialised yet. Just because you call a method from an arbitary object inside a transaction does not mean that it will automatically fetch your corresponding database object. Hibernate is feature-rich, but in the end it is not magic.
You should try to query for an Administrator. Here are some hints:
Query query = session.createQuery("select Administrator where id = :admin_id");
query.setParameter("admin_id", 1);
Administrator result = (Administrator) query.getSingleResult();
I'm using Jersey + spring + hibernate4.17 to develop api system; The problem is if the cleaFields is called twice at same time, the 2nd call will throw an exception as below,
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:81)
at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:73)
at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.checkRowCounts(BatchingBatch.java:133)
at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.performExecution(BatchingBatch.java:110)
at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.doExecuteBatch(BatchingBatch.java:101)
at org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl.execute(AbstractBatchImpl.java:149)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.executeBatch(JdbcCoordinatorImpl.java:162)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:357)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:280)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:326)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1213)
The clearFields method in the Controller,
#Transactional(isolation=Isolation.REPEATABLE_READ)
public void clearFields(Integer userId) {
User user = this.userDao.get(userId);
user.getFields().clear();
userDao.flush(); //call the current session.flush(); this line can throw exception.
}
User Entity class
#Entity
#Table(name="users")
#NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id", unique = true, nullable = false)
private int userId;
#OneToMany(mappedBy = "user", cascade = { CascadeType.ALL }, targetEntity = UserProfile.class, fetch = FetchType.LAZY, orphanRemoval=true)
#OrderBy("id")
private List<UserProfile> fields = new ArrayList<UserProfile>();
public User() {
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public List<UserProfile> getFields() {
return fields;
}
public void setFields(List<UserProfile> fields) {
this.fields = fields;
}
}
UserProfile class,
#Entity
#Table(name="user_profiles")
public class UserProfile implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column(name="field_name")
private String fieldName;
#ManyToOne(targetEntity = User.class, fetch = FetchType.LAZY)
#JoinColumn(name="user_id")
private User user;
private String value;
public UserProfile() {
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFieldName() {
return this.fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public String getValue() {
return this.value;
}
public void setValue(String value) {
this.value = value;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
I did some research, the root cause is if the 2nd calling get some fields, and before delete them, the 1st calling already delete all fields from database.
In another word, the 2nd calling try to delete some records which already were deleted by others.
How can I solve the problem?
I am trying to connect to a mysql db from java using hibernate. I am trying to understand whether it really worth using an ORM such as hibernate for relations or not. Especially specfying relationships with annotations seems quite irritating to me. So for a friendship table I would like to see the friendship requests of a particular user by using the foreign key from a users table.
In hibernate classes for helper table holds a field which represents the main table too. So instead of keeping the relation with a simple int, it holds a User class as a primary field. This might be useful, if you need to access the user object but in some cases you only need the foreign key id.
I put the sample code I have written for two tables, Users and UserFriendRequests. Is this the best approach to represent the following two tables? I feel like this is quite overkill for representing such basic tables. I would prefer using Hibernate just for connection and representing tables individually and handle relations manually. Would you recommend this approach? I would appreciate if you can share your ideas and documents about best practices.
Users table have the following columns
userId primary, auto increment
facebookId unique
username
createdAt date
lastLogin date
lastNotifiedAt date
UserFriendRequests table have the following columns:
firstUser foreignkey of userId from Users table
secondUser foreignkey of userId from Users table
PrimaryKey(firstUser, secondUser)
Representation of User table
#Entity
#Table(name = "Users", catalog = "example_schema", uniqueConstraints = {
#UniqueConstraint(columnNames = "userId"),
#UniqueConstraint(columnNames = "facebookId")})
public class User implements Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "userId", unique = true, nullable = false)
private int userId;
#Column(name = "facebookId", unique = true, nullable = false)
private String facebookId;
#Column(name = "userName", nullable = false)
private String userName;
#Column(name = "createdAt", nullable = false)
#Temporal(javax.persistence.TemporalType.DATE)
private Date createdAt;
#Column(name = "lastLogin")
#Temporal(javax.persistence.TemporalType.DATE)
private Date lastLogin;
#Column(name = "lastNotifiedAt")
#Temporal(javax.persistence.TemporalType.DATE)
private Date lastNotifiedAt;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "id.firstUser") // I would prefer to fill these relations manually
private List<UserFriendRequest> userFriendRequests = Lists.newArrayList();
#Transient
private boolean newUser;
public User() {
this.createdAt = new Date();
this.newUser = false;
}
public User(int userId) {
this();
this.userId = userId;
}
public User(String facebookId, String userName) {
this();
this.facebookId = facebookId;
this.userName = userName;
}
public User(int userId, String facebookId, String userName) {
this(facebookId, userName);
this.userId = userId;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getFacebookId() {
return facebookId;
}
public void setFacebookId(String facebookId) {
this.facebookId = facebookId;
}
public boolean isNewUser() {
return newUser;
}
public void setNewUser(boolean newUser) {
this.newUser = newUser;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public Date getLastLogin() {
return lastLogin;
}
public void setLastLogin(Date lastLogin) {
this.lastLogin = lastLogin;
}
public Date getLastNotifiedAt() {
return lastNotifiedAt;
}
public void setLastNotifiedAt(Date lastNotifiedAt) {
this.lastNotifiedAt = lastNotifiedAt;
}
public List<UserFriendRequest> getUserFriendRequests() {
return userFriendRequests;
}
public void setUserFriendRequests(List<UserFriendRequest> userFriendRequests) {
this.userFriendRequests = userFriendRequests;
}
#Override
public int hashCode() {
int hash = 7;
hash = 53 * hash + this.userId;
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final User other = (User) obj;
if (this.userId != other.userId) {
return false;
}
return true;
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
}
Representation of UserFriendRequests table
#Entity
#Table(name = "UserFriendRequests", catalog = "example_schema")
public class UserFriendRequest implements Serializable {
#Embeddable
public static class UserFriendRequestKey implements Serializable {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "firstUser", nullable = false)
//Instead of user class I would prefer to keep only the int field. If I would need the user object I would handle it myself.
private User firstUser;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "secondUser", nullable = false)
private User secondUser;
public UserFriendRequestKey() {
}
public UserFriendRequestKey(User firstUser, User secondUser) {
this.firstUser = firstUser;
this.secondUser = secondUser;
}
public User getFirstUser() {
return firstUser;
}
public void setFirstUser(User firstUser) {
this.firstUser = firstUser;
}
public User getSecondUser() {
return secondUser;
}
public void setSecondUser(User secondUser) {
this.secondUser = secondUser;
}
#Override
public int hashCode() {
int hash = 7;
hash = 89 * hash + Objects.hashCode(this.firstUser);
hash = 89 * hash + Objects.hashCode(this.secondUser);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final UserFriendRequestKey other = (UserFriendRequestKey) obj;
if (!Objects.equals(this.firstUser, other.firstUser)) {
return false;
}
if (!Objects.equals(this.secondUser, other.secondUser)) {
return false;
}
return true;
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
}
#Id
private UserFriendRequestKey id;
#Column(name = "requestedAt", nullable = false)
#Temporal(javax.persistence.TemporalType.DATE)
private Date requestedAt;
public UserFriendRequest() {
}
public UserFriendRequest(UserFriendRequestKey id) {
this.id = id;
this.requestedAt = new Date();
}
public UserFriendRequestKey getId() {
return id;
}
public void setId(UserFriendRequestKey id) {
this.id = id;
}
public Date getRequestedAt() {
return requestedAt;
}
public void setRequestedAt(Date requestedAt) {
this.requestedAt = requestedAt;
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
}
Hibernate has a steep learning curve but it also has the following advantages:
Insert/Updates are easier due to "dirty checking". Once you have the service in place, you can easily add new fields without changing a line in your service. You just need to add new columns and populate those and Hibernate will take care of the persistence part.
Hibernate can solve the "lost update" problem because of it's optimistic locking concurrency control.
Integration testing is easier, since you can generate the schema automatically for your in-memory database (HSQLDB, H2, Derby)
It has a caching plug-in support (through third party 2nd level caching providers), some providers allowing you to have both "transactional" and "clustered" caches.
It has a built-in AUDIT support (Envers)
So it's not a 'default' persistence solution, since there are millions of web apps written in PHP with no ORM framework that are successfully running in production.
I think Hibernate has much more sense for enterprise applications where caching, auditing, concurrency reliability are mandatory non-functional requirements.
Hibernate used for Object relational mapping.You write HQL query,If you are using hibernate.We used hibernate in different approach.let me tell how to do.
Using hibernate plugin,you can genrate pojo classes for every table present in the DB.So no need to write a pojo class from your side and many xml related files also.You must need one persisten.xml file on your project.