H2 database columns and values don't converge JAVA Spring - java

I am new one at java and spring framework and have this problem. I have class, which has fields, that should be columns in H2. It looks like this:
package com.bankapp.bankwebapplication.models;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class PersonClient implements Client {
#Id
#Column(nullable = false, unique = true)
private Long id;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
#Column(nullable = false)
private String firstName;
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
#Column(nullable = false)
private String lastName;
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
#Column(nullable = false)
private String address;
public String getAddress() { return address; }
public void setAddress(String address) { this.address = address; }
#Column
private String workPhone;
public String getWorkPhone() { return workPhone; }
public void setWorkPhone(String workPhone) { this.workPhone = workPhone; }
#Column
private String homePhone;
public String getHomePhone() { return homePhone; }
public void setHomePhone(String homePhone) { this.homePhone = homePhone; }
#Override
public void getDetails() {
}
}
Also, I have data.sql file that inserts 1 value into that table:
INSERT INTO person_client VALUES (1, 'firstName', 'lastName', 'paper street', '+123123', '+321321')
So, the problem is that it looks like this:
Why? And how can I fix that?

Always specify the target columns in INSERT statements:
INSERT INTO person_client
(id, first_name, last_name, address, home_phone, work_phone)
VALUES
(1, 'firstName', 'lastName', 'paper street', '+123123', '+321321')
If you don't specify the target columns, the values are matched by position and apparently the columns are created in a different order than you think they are.

agree with #a_horse_with_no_name, if you not specify column names it will insert based on the position/index. And all your java variables are in string that is the reason it does't throw any classcast exception.

Related

How can I let Hibernate auto-create tables in my database?

here is the background:
I am using IntelliJ 2021.3 for Spring development.
My current task is to let an embedded H2 database get initialized with a table schema and test data.
My current application should basically support that behaviour. But what am I missing?
Now I did my research googling through many articles that describe the auto-generation of tables in a database with hibernate mostly in the same way: I have to set spring.jpa.hibernate.ddl-auto in the aplication.properties to create.
spring.h2.console.enabled=true
spring.jpa.hibernate.ddl-auto=create
I have set up my Entities like this here:
package com.learning.classes;
import javax.persistence.*;
import java.util.List;
#Entity
public class Course {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Course_Id")
private long courseId;
#Column(name = "Course_Name")
private String courseName;
#OneToMany(mappedBy = "course", cascade = CascadeType.PERSIST)
private List<Student> student;
public Course() {
}
public Course(long courseId, String courseName) {
this.courseId = courseId;
this.courseName = courseName;
}
public long getCourseId() {
return courseId;
}
public void setCourseId(long courseId) {
this.courseId = courseId;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public List<Student> getStudent() {
return student;
}
public void setStudent(List<Student> student) {
this.student = student;
}
}
and
package com.learning.classes;
import javax.persistence.*;
#Entity
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Student_Id")
private long studentId;
#Column(name = "First_Name")
private String firstName;
#Column(name = "Last_Name")
private String lastName;
#ManyToOne(fetch = FetchType.EAGER)
private Course course;
public Student() {
}
public Student(long studentId, String firstName, String lastName) {
this.studentId = studentId;
this.firstName = firstName;
this.lastName = lastName;
}
public long getStudentId() {
return studentId;
}
public void setStudentId(long studentId) {
this.studentId = studentId;
}
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 Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
}
Now I know that there ain't any data to get inserted when starting the app, but at least I should see my tables when I access my H2 via the console.
Thanks in advance.
So I found out why nothing is working, and to be fully open about it: it was my fault.
I arranged the packages in a way where the Main was not able to read the other packages. The main package was not in the same directory as the others so nothing could happen.
I am writing this so anyone can account on that.
Nevertheless thanks for everyone who has contributed to this topic.
This question is closed.

Column 'encrypted_password' cannot be null?

Im working on a web service using Java and spring-data-jpa. I setted different endpoints that works fine. Now I implemented logics in the post method and get return an error that I can't solve.
I use postman and when I try to make a post request with id,username,lastname and password i get an error 500 and the server return me this error:
java.sql.SQLIntegrityConstraintViolationException: Column 'encrypted_password' cannot be null
package com.nicolacannata.Appws.entity;
import javax.persistence.*;
import java.io.Serializable;
#Entity(name="users")
public class UserEntity implements Serializable{
private static final long serialVersionUID = 8076405899207283205L;
#Id
#GeneratedValue
private long id;
#Column(nullable = false)
private String userId;
#Column(nullable = false, length = 50)
private String firstName;
#Column(nullable = false, length = 50)
private String lastName;
#Column(nullable = false, length = 50)
private String email;
#Column(nullable = false)
private String encryptedPassword;
private String emailVerificationToken;
#Column(nullable = false)
private boolean emailVerificationStatus = false;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
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;
}
public String getEncryptedPassword() {
return encryptedPassword;
}
public void setEncryptedPassword(String encryptedPassword) {
this.encryptedPassword = encryptedPassword;
}
public String getEmailVerificationToker() {
return emailVerificationToken;
}
public void setEmailVerificationToker(String emailVerificationToker) {
this.emailVerificationToken = emailVerificationToker;
}
public boolean isEmailVerificationStatus() {
return emailVerificationStatus;
}
public void setEmailVerificationStatus(boolean emailVerificationStatus) {
this.emailVerificationStatus = emailVerificationStatus;
}
}
You declared that attribute encryptedPassword cannot be null. The exception means, that this attribute was null when you attempted to save it to database. Either you forgot to set this attribute. Or you set it (you called setter), but the new value was null. To resolve the problem, set this attribute to a not-null value before saving to DB.
You have #Column(nullable = false) for private String encryptedPassword; and you are passing only id, username, lastname and password. which breaks the condition nullable = false and results in java.sql.SQLIntegrityConstraintViolationException: Column 'encrypted_password' cannot be null
Solution
Set #Column(nullable = true)
OR
Pass the value for encryptedPassword

How to update one field in my Entity using JPA Repository

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.

Creating an instance of a class and at the same time create an instance of another class that depends on the first class [duplicate]

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

how to write java hibernate many to many relationship retrieving query

I have two tables as specified below. I want to write a query to get all the contacts of a particular group.(According to group id). Please help me.
Thanks in advance.
1.this contacts table , which has many has many to many relationship with contact groups table.
#Entity
#Table(name="contacts")
public class Contacts implements Serializable {
private Long id;
private String userId;
private String emailId;
private Set<ContactGroups> contactGroups;
private String firstName;
private String lastName;
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name="user_id")
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
#Column(name="email_id")
public String getEmailId() {
return emailId;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
#ManyToMany(targetEntity = ContactGroups.class, cascade = {CascadeType.ALL},fetch=FetchType.EAGER)
#JoinTable(name="contact_group",
joinColumns=#JoinColumn(name="c_id", referencedColumnName="id"),
inverseJoinColumns=#JoinColumn(name="g_id", referencedColumnName="id")
)
public Set<ContactGroups> getContactGroups() {
return contactGroups;
}
public void setContactGroups(Set<ContactGroups> contactGroups) {
this.contactGroups = contactGroups;
}
#Column(name="first_name")
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#Column(name="last_name")
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
#Entity
#Table(name="contact_groups")
public class ContactGroups implements Serializable{
private Long id;
private String groupName;
private String userName;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name="user_name")
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
#Column(name="group_name")
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
}
select c from Contacts c
inner join c.contactGroups group
where group.id = :groupId
But everything would be simpler if
you named your entities ContactGroup and Contact (without the final s)
you mapped the association as a bidirectional one. It would allow getting the ContactGroup by ID, and just call getContacts() to get its contacts.
select c from Contacts c, ContactGroups g
where c.contactGroups.id = g.id
and g.id = 'whatever id you want'

Categories