Reputation:
I'm trying to update a 'Student' from PostgreSQL Database, but it only deletes the old value and creates a new id value for the new Student, with all the other fields empty.
Here is the class for "Student", from "Persistence" package, "Entity" subpackage:
@Entity
@Table(name = "student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "student_id_seq")
@SequenceGenerator(name="student_id_seq", sequenceName = "student_id_seq", allocationSize=1)
@Column(name = "id", nullable = false)
private Integer id;
@Column
private String studentName;
@Column
private Integer studentGroup;
@Column
private String courseName;
@Column
private Integer studentGrades;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String name) {
this.studentName = name;
}
public Integer getStudentGroup() {
return studentGroup;
}
public void setStudentGroup(Integer group) {
this.studentGroup = group;
}
public String getCourseName() { return courseName;}
public void setCourseName(String courseName) {this.courseName = courseName;}
public Integer getStudentGrades() {
return studentGrades;
}
public void setStudentGrades(Integer grades) {
this.studentGrades = grades;
}
}
This is how my interface for "Repository" subpackage (also from "Persistence" package) looks like :
public interface StudentRepository extends JpaRepository<Student, Integer> {}
In "StudentService" ("Business" package) I have the operations for create, update, delete and view all the students I have :
@Service
public class StudentService {
@Inject
StudentRepository studentRepository;
public List<Student> getAllStudentssWithCourses()
{
return studentRepository.findAll();
}
public Student create(Student newStudent)
{
return studentRepository.save(newStudent);
}
public void update(Student newStudent, Student oldStudent){
if(oldStudent == null){
System.out.println("ERROR! Student does not exist !!!");
} else{
newStudent.setId(oldStudent.getId());
newStudent.setStudentName(newStudent.getStudentName());
newStudent.setStudentGroup(newStudent.getStudentGroup());
newStudent.setCourseName(newStudent.getCourseName());
newStudent.setStudentGrades(newStudent.getStudentGrades());
studentRepository.save(newStudent);
}
}
public void delete(Student student){
studentRepository.delete(student);
}
}
In "Controller" package, I have :
@Controller
public class StudentController {
@Inject
StudentService studentService;
@RequestMapping(value = "/student", method = RequestMethod.GET)
public ModelAndView getStudents()
{
List<Student> studentList = studentService.getAllStudentssWithCourses();
ModelAndView mav = new ModelAndView("student_view");
mav.addObject("studentsWithCoursesList", studentList);
mav.addObject("newStudent", new Student());
return mav;
}
@RequestMapping(value = "/student", method = RequestMethod.POST)
public ModelAndView postStudent(@RequestParam(value = "action") String action,@ModelAttribute(value = "newStudent") Student newStudent)
{
if(action.equals("Create Student"))
studentService.create(newStudent);
else if(action.equals("Update Student"))
studentService.update(new Student(), newStudent);
else
studentService.delete(newStudent);
return new ModelAndView("redirect:student");
}
}
My "student_view" in html looks like :
<body background = "https://www.itmagazine.us/wp-content/uploads/2017/10/6f6499a403cf64afea180b6419def4ef.jpg">
<h1>Welcome, student user !</h1>
<table border="1">
<thead>
<tr>
<th>student.ID</th>
<th>student.NAME</th>
<th>student.GROUP</th>
<th>student.COURSE</th>
<th>student.GRADES</th>
</tr>
</thead>
<tbody>
<tr th:each="student : ${ studentsWithCoursesList }">
<td th:text="${ student.id }">ID</td>
<td th:text="${ student.studentName }"></td>
<td th:text="${ student.studentGroup }"></td>
<td th:text="${ student.courseName }"></td>
<td th:text="${ student.studentGrades }"></td>
</td>
</tr>
</tbody>
</table>
<br/>
<br/>
<br/>
<form th:object="${newStudent}" method = "POST">
<div class="col-sm-12">
<label>Student ID</label>
<input type = "text" th:field="*{id}"/>
</div>
<div class="col-sm-12">
<label>Student Name</label>
<input type = "text" th:field="*{studentName}"/>
</div>
<div class="col-sm-12">
<label>Student Group</label>
<input type = "text" th:field="*{studentGroup}"/>
</div>
<div class="col-sm-12">
<label>Course Name</label>
<input type = "text" th:field="*{courseName}"/>
</div>
<div class="col-sm-12">
<label>Student Grades</label>
<input type = "text" th:field="*{studentGrades}"/>
</div>
<button type="submit" class = "btn btn-primary" name = "action" value="Create Student">ADD Student</button>
<button type="submit" class = "btn btn-primary" name = "action" value="Update Student">EDIT Student</button>
<button type="submit" class = "btn btn-primary" name = "action" value="Delete Student">DELETE Student</button>
</form>
</body>
My main class :
@SpringBootApplication()
public class Assignment2 {
public static void main(String[] args){
SpringApplication.run(Assignment2.class, args);
}
}
In my "application.properties", I have :
spring.jpa.database = POSTGRESQL
spring.jpa.show-sql = false
spring.jpa.hibernate.ddl-auto = validate
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation = true
spring.datasource.driverClassName = org.postgresql.Driver
spring.datasource.url = jdbc:postgresql://localhost:5432/ps2
spring.datasource.username = postgres
spring.datasource.password = root
spring.thymeleaf.cache = false
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
server.port = 8090
My database in PostgreSQL :
CREATE TABLE public.student
(
id integer NOT NULL,
student_name character varying COLLATE pg_catalog."default",
student_group integer,
course_name character varying COLLATE pg_catalog."default",
student_grades integer,
CONSTRAINT "Student_pkey" PRIMARY KEY (id)
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public.student
OWNER to postgres;
-----
CREATE SEQUENCE public.student_id_seq;
ALTER SEQUENCE public.student_id_seq
OWNER TO postgres;
Finally, in "pom.xml", I have :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo1</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.2.3.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.1.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/postgresql/postgresql -->
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.1-901-1.jdbc4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Upvotes: 1
Views: 2397
Reputation: 25976
The GenerationType.IDENTITY relies on a database auto-increment column to generate the id.
Your Student.id column in the dB is clearly not auto-increment.
I believe that standard syntax for auto-increment is available since Postgres10
See also https://thoughts-on-java.org/jpa-generate-primary-keys/ for an intro on different generation strategies. And the following question How to choose the id generation strategy when using JPA and Hibernate
Summing up SEQUENCE is the best available option, IDENTITY is only a good choice when you cannot use SEQUENCE because it disables JDBC batch updates.
Upvotes: 1
Reputation: 126
this question was already asked before.
In conclusion, you should use :
@GeneratedValue(strategy = GenerationType.SEQUENCE)
It's because IDENTITY can only be used for these dbs:
Sybase, My SQL, MS SQL Server, DB2 and HypersonicSQL.
See https://stackoverflow.com/a/29028369/6884722
Upvotes: 0