Как сохранить нового студента, который содержит объекты, но не создавать эти объекты, потому что они уже существуют в базе данных?

Я хочу сохранить учащегося, а у учащегося есть объект TargetAudience в качестве атрибута. Эти целевые аудитории уже жестко запрограммированы в моей базе данных. (целевая аудитория = кампус + специальность). Теперь, когда я публикую вот так:

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

это не работает, потому что каждый раз он создает новый объект для кампуса, и поскольку я использую имя в качестве первичного ключа, он генерирует исключение. Не следует ли spring data jpa искать, существует ли объект, а затем использовать его вместо этого? Или как я могу заставить это сделать?

Извините, если что не так, пишу первый раз

студент.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;

}

Кампус.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;
}
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
0
0
26
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

С каким исключением вы сталкиваетесь при попытке сохранить? Трассировка стека была бы более полезной. Однако вы можете обойти это двумя способами.

Либо, Если вы хотите полностью избежать сохранения TargetAudience, вы можете аннотировать свойство TargetAudience в аннотации @Transient, чтобы оно не учитывалось при сохранении базы данных.

Или, JPA каждый раз пытается сохранить объект с новым первичным ключом, потому что объект находится в отсоединенном состоянии (если ваш провайдер JPA находится в спящем режиме, который является провайдером JPA по умолчанию). Вы должны изменить метод registerStudent() в StudentService, например:

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

Итак, вы явно извлекаете TargetAudience из базы данных и устанавливаете его для объекта студента, который вы получаете. Таким образом, выбранный targetAudience будет находиться в постоянном состоянии (не отсоединен) и не будет пытаться снова назначить новый первичный ключ.

большое спасибо, я многому научился из вашего ответа, и теперь это работает!

Japerre 10.04.2022 16:57

Другие вопросы по теме