I have two entity classes that represent two tables in my database.
The two tables are User and Student. The Student class(userID, studentID, classID) inherits from the User class(id, firstName, lastName, email).
When I query the database for students, I have a List returned. I then want to use that list to iterate over and display the firstName,lastName,email,and classID for each student. However, it only displays the classID. I believe this is because the object is of a Student that only contains three fields (userID, studentID, classID) and doesn't doesn't contain the names and email. However, because the Student class extends the User class, I thought it should still be able to get the other fields.
Here are my classes
User
public class User {
private int id;
private String firstName;
private String lastName;
private String email;
public User(){
}
public String getFullName(){
return firstName +" "+ lastName;
}
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 getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Student
public class Student extends User {
private int userID;
private int studentID
private int classID
public int getUserID() {
return userID;
}
public void setUserID(int userID) {
this.userID = userID;
}
public int getStudentID() {
return studentID;
}
public void setStudentID(int studentID) {
this.studentID = studentID;
}
public int getClassID() {
return classID;
}
public void setClassID(int classID) {
this.classID = classID;
}
}
JSP
<c:forEach items="${students}" var="student">
<tr>
<td>${student.firstName} ${student.lastName}</td>
<td>${student.email}</td>
<td>${student.classID}</td>
</tr>
</c:forEach>
In my controller class
List<Student> students = getStudents();
output.addObject("students", students);
How can I get it to display, user.firstName, user.lastName, user.email, student.classID
The JSP code seems fine.
If the values are not available in the Student object and should be because of the hierarchy, the problem lies in the code that populates the Student objects after the query is done. You might want to validate how a Student object is created and why the fields which belong to the User object are not set.
Related
I am trying to build a table that can be modified and stored in a sql database. I am using mybatis to access my sql database. I want to be able to take a String from the user and add a column to the existing table that I have. In order to add a column to the sql table, I need to modify the class that fetches the data, and this class needs to have an instance variable added and the constructor modified to be able to fetch the data.
For example, This is one of my Mapper classes that relies on the Employee class to fetch data from the database.
#Mapper
public interface EmployeeMapper {
#Select("SELECT * FROM employee")
List<Employee> findEmployees();
#Select("SELECT * FROM employee WHERE list_UserName = #{list};")
List<Employee> employeeForUser(String list);
#Insert("INSERT INTO employee(name, email, position, list_UserName) values (#{name}, #{email}, #{position}, #{list_UserName});")
void addEmployee(Employee employee);
#Delete("DELETE FROM employee WHERE id = #{id}")
void deleteEmployee(int id);
}
Employee Class:
public class Employee {
private int id;
private String name;
private String email;
private String position;
private String list_UserName;
public Employee(int id, String name, String email, String position, String list_UserName) {
this.id = id;
this.name =name;
this.email = email;
this.position = position;
this.list_UserName = list_UserName;
}
public String getList_UserName() {
return list_UserName;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public String getPosition() {
return position;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setEmail(String email) {
this.email = email;
}
public void setPosition(String position) {
this.position = position;
}
}
Here is my controller for this case:
#RequestMapping(value="/list", method = RequestMethod.POST)
public String newEmployee(Model model, #RequestParam String EmployeeName, #RequestParam String EmployeeEmail, #RequestParam String EmployeePosition, HttpSession session) {
if(!sessionFound(session.getId())){
return "redirect:/login";
}
if(isNewEmployee(returnUser(session.getId()).getUser_name(), EmployeeName, EmployeeEmail, EmployeePosition)) {
Employee temp = new Employee(0, EmployeeName, EmployeeEmail, EmployeePosition, returnUser(session.getId()).getUser_name());
employeeMapper.addEmployee(temp);
return "redirect:/list";
}
model.addAttribute("employeeMessage", "Employee Already Exists");
return "redirect:/list";
}
In this case, I want to be able to alter the table(which I know how to do) and add an instance variable to the Employee class based on the User's request(which I do not know how to do). How do I do that?
I have Entity with 3 fields: id, lastname and phoneNumber. I want to create method which works for update all fields or only one or two.
I use Hibernate and JPA Repository.
When I try to update all fields everything works well but when for example i want to update only lastname without changing of phoneNumber I have in output null insted of old phoneNumber.
Here is my method from Controller:
#PutMapping("/students/update/{id}")
public String updateStudentById(#ModelAttribute Student student, #ModelAttribute StudentDetails studentDetails,
String lastname, String phoneNumber,
#PathVariable Long id) {
Optional<Student> resultOptional = studentRepository.findById(id);
//Student result =resultOptional.get();
resultOptional.ifPresent((Student result) -> {
result.getStudentDetails().setPhoneNumber(studentDetails.getPhoneNumber()); result.getStudentDetails().setLastname(studentDetails.getLastname());
studentRepository.save(result);
});
return "Student updated";
}
The class for update:
#DynamicUpdate
#Entity
public class StudentDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="lastname")
private String lastname;
#Column(name="phone_number")
private String phoneNumber;
public StudentDetails() {
}
public StudentDetails(Long id, String lastname, String phoneNumber) {
this.id = id;
this.lastname = lastname;
this.phoneNumber = phoneNumber;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
The class which has relation with StudentDetails:
#Entity
#Table(name = "student")
#DynamicUpdate
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#Column(name = "email")
private String email;
//#OneToMany(mappedBy = "student")
#ManyToMany
#JoinTable(name="course_student",joinColumns = #JoinColumn(name="student_id"),
inverseJoinColumns = #JoinColumn(name="course_id"))
private List<Courses> courses;
#OneToOne(cascade = CascadeType.ALL)
// #JoinColumn(name="studen/_details_id") // with this we have dobule student_details column
private StudentDetails studentDetails;
public List<Courses> getCourses() {
return courses;
}
public void setCourses(List<Courses> courses) {
this.courses = courses;
}
public StudentDetails getStudentDetails() {
return studentDetails;
}
public void setStudentDetails(StudentDetails studentDetails) {
this.studentDetails = studentDetails;
}
// Methods for StudentViewController
public String getLastname(){
return studentDetails.getLastname();
}
public String getPhoneNumber(){
return studentDetails.getPhoneNumber();
}
public Student() {
}
public Student(String name, String email, StudentDetails studentDetails) {
// this.id = id;
this.name = name;
this.email = email;
this.studentDetails = studentDetails;
}
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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
'}';
}
}
I was looking for solution and I added #DynamicUpdate but still it doesn't work.
Your code works properly. When you only provide lastName parameter in your request, then the phoneNumber parameter will be mapped to null so you override the phoneNumer property in your entity with this null value.
Change the code in the following way:
resultOptional.ifPresent((Student result) -> {
if(studentDetails.getPhoneNumber()!=null) {
result.getStudentDetails().setPhoneNumber(studentDetails.getPhoneNumber());
}
if(studentDetails.getLastname()!=null) {
result.getStudentDetails().setLastname(studentDetails.getLastname());
}
studentRepository.save(result);
});
Unfortunately it raises an other problem: How will you delete these fields? (How can you set them explicitly to null? )
A possible solution if you check for the "" (empty string) and set the property to null if the parameter is empty string.
It will be a quite messy code anyway...
You should consider using the Spring Data Rest package. It automatically creates all of the standard REST endpoints for your entities and handles all of these PUT/PATCH/POST/DELETE issues out of the box.
why don't you just set the params of your request in you setters?
resultOptional.ifPresent((Student result) -> {
result.getStudentDetails().setPhoneNumber(phoneNumber);
result.getStudentDetails().setLastname(lastname);
studentRepository.save(result);
});
You forget set #OneToOne mapping in StudentDetails - StudentDetails also need field of type Student which will be annotated #OneToOne.
Also you have to ensure, that all of entity fields will be filled - read more about fetch types.
This question already has answers here:
Hibernate: duplicate key value violates unique constraint
(4 answers)
Closed 6 years ago.
EDIT:How is this question different from the one linked?
I think this question is different because it seems as if it is caused by JPA trying to add another user with the same id, because of a foregin key value in the class (Student) being added. The issue linked seems to be caused by not generateing the ids automatically.
I have a method that creates a User and returns a User. I pass this User to another method to create a Student. The user is a student. But I can't do this because I get :
org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "pk_user_id"
Detail: Key (user_id)=(7001) already exists.
My methods in the backing bean looks like this:
public Users2 addUser(String username, String password, String emailadress,
String firstname, String lastname) {
Users2 u = new Users2();
u.setUsername(username);
u.setPassword(password);
u.setEmailaddress(emailadress);
u.setFirstname(firstname);
u.setLastname(lastname);
System.out.println(em + ": Adding course " + u);
em.persist(u);
em.flush();
System.out.println(u.getUser_id());
return u;
}
public void addStudent(Users2 u2) {
Student s = new Student();
s.setUser_id(u2.getUser_id());
s.setUsername(u2.getUsername());
s.setLastname(u2.getLastname());
s.setFirstname(u2.getFirstname());
s.setPassword(u2.getPassword());
s.setEmailaddress((u2.getEmailaddress()));
em.persist(s);
}
My method in the Jsf bean looks like this:
#Inject
DbStore store;
public String CreateUser(){
long usrid;
String username = this.username;
String password = this.password;
String emailadress = this.emailaddress;
String firstname = this.firstname;
String lastname = this.lastname;
Users2 u1 = store.addUser(username, password, emailadress, firstname, lastname);
//System.out.println(usrid);
String role = this.role;
if(this.role.equals("Student"))
store.addStudent(u1);
return "admin_listcourses.xhtml";
}
My entities:
import javax.persistence.Id;
import javax.validation.constraints.Max;
import java.util.List;
import java.util.Set;
#Entity
#Table(name = "student")
#SecondaryTable(name = "users2", pkJoinColumns=#PrimaryKeyJoinColumn(name="user_id", referencedColumnName="user_id"))
public class Student {
/**
* Created by Elev1 on 2016-08-25.
*
*/
#Id
#SequenceGenerator(name="student_student_id_seq",
sequenceName="student_student_id_seq",
allocationSize=1)
#GeneratedValue(strategy = GenerationType.SEQUENCE,
generator="seq")
#Column(name = "student_id", updatable=false)
private long student_id;
#Column(table="users2", name="username")
private String username;
#Column(table="users2", name="firstname")
private String firstname;
#Column(table="users2", name="lastname")
private String lastname;
#Column(table="users2", name="password")
private String password;
#Column(table="users2", name="emailaddress")
private String emailaddress;
#Column(table="users2", name="user_id")
private long user_id;
#ManyToMany
#JoinTable(name="student_course",
joinColumns=
#JoinColumn(name="student_id", referencedColumnName="student_id"),
inverseJoinColumns=
#JoinColumn(name="course_id", referencedColumnName="course_id")
)
// public List<Course> getCourses() { return courses ; }
public List<Course> courses;
//Getters and setters
public long getStudent_id() {
return student_id;
}
public void setStudent_id(long student_id) {
this.student_id = student_id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
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 List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
public long getUser_id() {
return user_id;
}
public void setUser_id(long user_id) {
this.user_id = user_id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmailaddress() {
return emailaddress;
}
public void setEmailaddress(String emailaddress) {
this.emailaddress = emailaddress;
}
}
package se.lexicon.entities;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
#Entity
public class Users2{
// ***********************
// ** Attributes **
// ***********************
#Id
#SequenceGenerator(name="users_user_id_seq",
sequenceName="users_user_id_seq",
allocationSize=1)
#GeneratedValue(strategy = GenerationType.SEQUENCE,
generator="seq")
private Long user_id;
#Column(name = "username", length = 64)
private String username;
private String password;
#Column(name = "emailaddress", length = 64)
private String emailaddress;
#Column(name = "firstname")
private String firstname;
#Column(name = "lastname")
private String lastname;
#Temporal(TemporalType.TIMESTAMP)
private Date last_login;
// ************************
// ** Constructors **
// ************************
// public User() {
// public User(Long user_id) {
// this.user_id = user_id;
// }
// public User(Long user_id, String username, String password, String emailaddress, ??? last_login) {
// this.user_id = user_id;
// this.username = username;
// this.password = password;
// this.emailaddress = emailaddress;
// this.last_login = last_login;
//}
// ******************************
// ** Getters & Setters **
// ******************************
public long getUser_id() {
return user_id;
}
public void setUser_id(long user_id) {
this.user_id = user_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 String getEmailaddress() {
return emailaddress;
}
public void setEmailaddress(String emailaddress) {
this.emailaddress = emailaddress;
}
public Date getLast_login() {
return last_login;
}
public void setLast_login(Date last_login) {
this.last_login = last_login;
}
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;
}
//}
}
EDIT: My solution. I removed the foregin_key constraint in the student table. I only kept student_id, course_id and user_id in the Student class. I removed all connections between Student and Users2 in the Student class, instead I use methods to get those from the Users2 class if a student_id is given. When a user is created, that is a Student, then a Student is added with the user_id of the user set as the user_id of the Student.
Now this isn't a very good solution, so if some one can solve my original problem I would be happy to accept the solution. But for now my solution will have to do.
When you persist a Student instance JPA will also create a row in the Users2 table with the user_id as foreign key to the row in the Student table. But there is already a row with the very same ID in the Users2, as you persisted a Users2 instance just before. That's the reason, why you are facing this SQLException.
To me it does not make much sense to use the SecondaryTable-approach here, as there might me Users which are no Students at all, right? But in your current model the Users table is storing a Foreign Key to the Student table..
In this case here it seems to be more appropriate to use inheritance (or maybe some composition) here, instaead of the SecondaryTable-approach.
A Student is-a User, so Student may inherit from User.
You will find a first overview how to define the mapping in this case here: https://en.wikibooks.org/wiki/Java_Persistence/Inheritance
I am trying to display a grid with tapestry based on this Tutorial, but i'm getting this error Class mypack.pages.User has been transformed and may not be directly instantiated
those are my classes User
public class User {
#NonVisual
private long id;
private String firstName;
private String lastName;
private int age;
public long getId() { return id; }
public void setId(long 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 int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public User(long id, String firstName, String lastName, int age) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
}
Bellilpage.java
public class Bellilpage {
#Property
private User user;
public List<User> getUsers() {
List<User> dd= new ArrayList<User>();
for(int x=0;x<1;x++)
{
Random rand = new Random();
long d= rand.nextInt(50);
User myuser = new User(d, "Name N° "+d, "lastName N "+d, (int) (d+15));
dd.add(myuser);
}
return dd; }
}
and finally this is how i try to display the grid in the web page
Bellilpage.tml
<html t:type="layout" title="tapestrythetest Index"
t:sidebarTitle="Framework Version"
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"
xmlns:p="tapestry:parameter">
<!-- A Zone is a component that can be updated in place, triggered by other components. -->
<t:zone t:id="zone">
<h1>List Users</h1>
<t:grid source="users" row="user">
<p:lastNameCell>
${user.lastname}
</p:lastNameCell>
</t:grid>
</t:zone>
<p:sidebar>
</p:sidebar>
</html>
Why am i gtting this error when i open Bellilpage.tml?
You are getting the error because mypack.pages is a T5 controlled package. Move your User class to a different package, e.g. to mypack.entities. More info at Component Classes, specifically the Component Packages section.
I was trying a simple hibernate populate the db example. There are two POJO's Employee and Address. When I tried to use both the Employee and Address constructor's with parameters to create two instances an error could not get constructor for org.hibernate.persister.entity.singletableentitypersisterwas thrown but the property accessor methods worked fine. Why did I get the error ?
Ok since I do not have the stack trace right now I shall rephrase my question are property accessor methods preferred over constructors in hibernate?
Employee POJO:
package many2one;
public class Employee {
public int id;
public String firstName;
public String lastName;
public int salary;
public Address address;
public Employee(){}
public Employee(String firstName,String lastName,int salary,Address address){
this.firstName = firstName;
this.lastName = lastName;
this.salary = salary;
this.address = address;
}
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
public String getFirstName(){
return firstName;
}
public void setFirstName(String fname){
this.firstName = fname;
}
public String getLastName(){
return lastName;
}
public void setLastName(String lname){
this.lastName = lname;
}
public int getSalary(){
return salary;
}
public void setSalary(int salary){
this.salary = salary;
}
public Address getAddress(){
return address;
}
public void setAddress(Address address){
this.address = address;
}
#Override
public String toString(){
return id+","+firstName+","+lastName+","+salary+","+address.getStreetName()+","+address.getCityName()+","+address.getStateName()+","+address.getZipcode();
}
}
Address POJO:
package many2one;
public class Address {
public int id;
public String streetName;
public String cityName;
public String stateName;
public String zipcode;
public Employee employee;
public Address(){
}
public Address(String sname,String cname,String statename,String zipcode){
this.streetName = sname;
this.cityName = cname;
this.stateName = statename;
this.zipcode = zipcode;
}
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
public String getStreetName(){
return streetName;
}
public void setStreetName(String streetname){
this.streetName = streetname;
}
public String getCityName(){
return cityName;
}
public void setCityName(String cname){
this.cityName = cname;
}
public String getStateName(){
return stateName;
}
public void setStateName(String statename){
this.stateName = statename;
}
public String getZipcode(){
return zipcode;
}
public void setZipcode(String zipcode){
this.zipcode = zipcode;
}
public Employee getEmployee(){
return employee;
}
public void setEmployee(Employee employee){
this.employee = employee;
}
}
`
Your class should have a default public constructor that does not take any arguments. That's the only constraint with respect to constructors when using Hibernate.
As for the exception, you are probably missing a setter for one of your fields or the setters don't follow the convention expected by Hibernate. But this can only be confirmed if you provide a full stack trace.
are property accessor methods preferred over constructors in
hibernate?
What do you mean by preffered? If you mean are property methods optional, then the answer is no. (Whcih could be one of the reasons for the exception in the first place)