user11391131
user11391131

Reputation:

Can't add and update values using Spring Boot connecting to PostgreSQL database

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

Answers (2)

Lesiak
Lesiak

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

PostgreSQL Autoincrement

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

Ricardo J. Chamorro
Ricardo J. Chamorro

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

Related Questions