简体   繁体   中英

How to insert record into database using spring jpa when there is no conflict

I have spring boot application that is connected with the PostgreSQL database using spring-data-jpa , here is my entity with nearly 40 fields

Now for saving the entity into database, I'm just using the studentRepository.save method

studentRepository.save(new StudentEntity());

DAO Entity

  @Table
  @Entity
  public class StudentEntity {

     @Id
     @Generate( using database sequenece)
     private long studentId;

     private String studentName;

     private String dept;

     private String age;
      ..
      ..
      }

Repository

 public interface StudentRepository implements JPARepository<Long, Student> {
   }

But now I have requirement, if there is any student record in table with name and dept I should not insert the new record, I know I can use PostgreSQL ON CONFLICT with native query for this, but if I use native query I have to specify all 40 fields in query and as method arguments which looks ugly.

Is there any way to make it simpler?

Example of native query

@Query(value = "insert into Users (name, age, email, status) values (:name, :age, :email, :status)", nativeQuery = true)

 void insertUser(@Param("name") String name, @Param("age") Integer age, @Param("status") Integer status, @Param("email") String email);

Use the database. Create a unique constraint on the 2 fields and trying to add multiple of those will be prevented.

Something like

ALTER TABLE StudentEntity ADD CONSTRAINT UQ_NAME_DEPT UNIQUE (studentName,dept);

This unique constraint will prevent the insertion of duplicate combinations.

You could also define an constraint on your JPA entity to automatically create the index for testing

@Table(uniqueConstraints=@UniqueConstraint(columnNames = {"studentName", "dept"})

No need of native query. You can do it by writing object oriented queries too. first check is there any record present in table by name and dept . If it returns null, then do your save.

StudentRepository.java

public interface StudentRepository implements JPARepository<Long, Student> {


@Query("FROM Student AS stu WHERE lower(stu.name) = lower(:studentName) AND lower(stu.dept) = lower(:dept)")
public Student findStudentByNameAndDept(@Param("studentName") String studentName, @Param("dept") String dept);

//if you have already duplicates in your db, then you can do the followings too..
@Query("FROM Student AS stu WHERE lower(stu.name) = lower(:studentName) AND lower(stu.dept) = lower(:dept)")
public List<Student> findAllStudentsByNameAndDept(@Param("studentName") String studentName, @Param("dept") String dept);

}

StudentService.java

if(studentRepository.findStudentByNameAndDept(name,dept)==null){
    //save
}else{
    //custom hanlding
    throw StudentExistsException("Student with the given name/dept exists");
}

OR
//if already duplicates exisited in db

if(studentRepository.findStudentByNameAndDept(name,dept).isEmpty()){
    //save
}else{
    //custom hanlding
    throw StudentExistsException("Student with the given name/dept exists");
}

If your priority is to reduce verbosity, as it is native sql you can avoid the names of the fields if you put them in the correct order, but you must put all the values of the table, even the null:

@Query(value = "insert into Users values (:name, :age, :email, :status)", nativeQuery = true)
 void insertUser(@Param("name") String name, @Param("age") Integer age, @Param("status") Integer status, @Param("email") String email);

Or instead of doing it with native insert, you can save if the method findByStudentNameAndDebt(studentName, dept), does not return any result. In StudentRepository (here native is not necessary):

@Query("SELECT a FROM Student as a WHERE lower(a.studentName) = lower(:studentName) AND lower(a.dept) = lower(:dept)")
    public Student findByStudentNameAndDebt(@Param("studentName") final String studentName, @Param("dept") final String dept);

And in your service:

if(studentRepository.findByStudentNameAndDebt(studentName, dept)==null) {
   studentRepository.save(new StudentEntity());
}

you can use a lightweight query to check whether a student with same name and department already exists

public interface StudentRepository implements JPARepository<Long, Student> {

@Query("SELECT CASE WHEN COUNT(c) > 0 THEN true ELSE false END FROM Student s WHERE s.studentName= :studentName AND s.dept= :dept")
    public boolean existsByNameAndDepartment(@Param("studentName") String studentName, @Param("dept") String dept);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM