Skip to content
Advertisement

how do i save a new student that contains entities, but don’t create these entities because they already exist in the database?

I want to save a student and a student has a TargetAudience object as an attribute. These target audiences are allready hardcoded in my database. (targetaudience = campus + major). Now when i post like this:

{
    "user": {
        "userName": "jan",
        "password": "tibo123",
        "role": "ROLE_STUDENT"
    },
    "targetAudience": {
        "majorCode": "IW E-ICT",
        "campus": {
            "name": "GroepT",
            "street": "Andreas Vesaliusstraat",
            "postalCode": "3000",
            "streetNr": "13"
        }
    }
}

it doesnt work because everythime it creates a new object for the campus and because i use name as a primary key it throws an exception. Shouldn’t spring data jpa look if the entity allready exists and then use that instead? Or how can i make it do this?

Sorry if this isn’t clear, it’s my first time posting

student.java:

package com.bachproject.demo.student;

import com.bachproject.demo.onderwerp.Onderwerp;
import com.bachproject.demo.targetAudience.TargetAudience;
import com.bachproject.demo.user.User;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.util.List;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {

    @Id
    @SequenceGenerator(
            name = "student_sequence",
            sequenceName = "student_sequence",
            allocationSize = 1
    )
    @GeneratedValue(
            strategy = GenerationType.SEQUENCE,
            generator = "student_sequence"
    )
    private Long studentId;

    @OneToOne(
            cascade = CascadeType.ALL,
            fetch = FetchType.EAGER,
            optional = true
    )
    @JoinColumn(
            name = "user_id",
            referencedColumnName = "userId"
    )
    private User user;

    @OneToOne(
            cascade = CascadeType.ALL,
            fetch = FetchType.EAGER,
            optional = true
    )
    @JoinColumn(
            name = "target_audience",
            referencedColumnName = "TargetAudienceId"
    )
    private TargetAudience targetAudience;

    //private List<Onderwerp> preferences;

}

StudentController.java

package com.bachproject.demo.student;

import com.bachproject.demo.onderwerp.Onderwerp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/students")
public class StudentController {

    @Autowired
    private StudentService studentService;

    @GetMapping
    @CrossOrigin(origins = "*")
    public List<Student> getStudents(){
        return studentService.getStudents();
    }

    @PostMapping("/register")
    @CrossOrigin(origins = "*")
    public Student registerStudent(@RequestBody Student student) {
        System.out.println(student);
        return studentService.registerStudent(student);
    }
}

StudentService.java:

package com.bachproject.demo.student;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class StudentService {

    @Autowired
    private StudentRepository studentRepository;

    public List<Student> getStudents() {
        return studentRepository.findAll();
    }

    public Student registerStudent(Student student) {
        return studentRepository.save(student);
    }
}

TargetAudience.java:

package com.bachproject.demo.targetAudience;

import com.bachproject.demo.campus.Campus;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TargetAudience {

    @Id
    @SequenceGenerator(
            name = "targetAudience_sequence",
            sequenceName = "targetAudience_sequence",
            allocationSize = 1
    )
    @GeneratedValue(
            strategy = GenerationType.SEQUENCE,
            generator = "targetAudience_sequence"
    )
    private Long TargetAudienceId;

    // for example IW E-ICT-> industriele wetenschappen Elektronica ICT
    private String majorCode;

    @OneToOne(
            cascade = CascadeType.ALL,
            fetch = FetchType.EAGER,
            optional = true
    )
    @JoinColumn(
            name = "campus",
            referencedColumnName = "name"
    )
    private Campus campus;

}

Campus.java:

package com.bachproject.demo.campus;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Campus {

    @Id
    private String name;

    private String street;
    private String postalCode;
    private String streetNr;
}

Advertisement

Answer

What exception are you facing while trying to save? A stack trace would’ve been more helpful. However, you can work around this in two ways

Either, If you want to avoid saving TargetAudience altogether, you can annotate the TargetAudience property in @Transient annotation so, it’ll not be considered for database saving.

Or, JPA is trying to save the object with new primary key every-time because the object is in detached state (if your JPA provider is hibernate, which is default JPA provider). You should modify registerStudent() method in StudentService like –

public Student registerStudent(Student student) {
    TargetAudience targetAudience = targetAudienceRepository.findByMajorCode(student.getTargetAudience().getMajorCode());
    student.setTargetAudience(targetAudience);
    return student;
}

So, you’re explicitly fetching TargetAudience from database and setting it to student object you’re getting. In this way, fetched targetAudience will be in persistent state (not detached) and it’ll not try to assign new primary key again.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement