Как мне сохранить родительскую сущность, не обновляя дочернюю сущность, где у них есть отношения многие ко многим? - PullRequest
0 голосов
/ 15 января 2019

У меня есть родительская сущность A, которая имеет много-много реалий с сущностью B и сущностью C, которые отображаются в таблице A_B и таблице A_C. При сохранении я хочу сохранить только A, A_B и A_c без сохранения B и C. Если я не использую cascadetype.all , я получаю " объект ссылается на несохраненный временный экземпляр - сохраните временный экземпляр перед сбросом ошибки ". Если я использую cascade.all, все таблицы обновляются.

Это мой родительский Entity Student (геттеры и сеттеры присутствуют, но не отображаются)

@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int studentId;
......
...... 
@ManyToMany()
@JoinTable(name = "student_preferredCountry",joinColumns = @JoinColumn(name 
= "studentId"),inverseJoinColumns = @JoinColumn(name = "countryId"))
private Set<Country> countries;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "student_preferred_course",joinColumns = @JoinColumn(name 
= "studentId"),inverseJoinColumns = @JoinColumn(name = "courseId"))
private Set<Course> courses;

Это мой дочерний объект. Курс

@Entity
public class Course {
private String courseName;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int courseId;
@ManyToMany(mappedBy = "courses")
private List<Student> coursestudents;

Это моя другая дочерняя сущность Страна

@Entity
public class Country {
@Id
private int countryId;
private String countryName;
@ManyToMany(mappedBy = "countries")
private List <Student> students;

Вот как я упорствую

public boolean studententry(@RequestBody Student stud){
studentRepository.save(stud);

Это пример запроса JSON

{

"studentFname": "fdfd",
"studentMname": "dfdf",
"studentLname": "fdf",
"studentFatherName": "fd",
"studentMotherName": "dfd",
"studentEmail": "dfd",
"studentAddress": "df",
"studentPhone": "df",
"countries": [
    {
        "countryId": "1",
        "countryName": "aus"
    },
    {
        "countryId": "2",
        "countryName": "newz"
    }
],
"courses": [
    {
        "course_id": "1",
        "course_name": "IELTS"
    },
    {
        "course_id": "2",
        "course_name": "TOEFL"
    }
    ]

}

В основном я хочу добавить все свойства ученика, student_courses, student_country без сохранения в таблице курса и страны

Ответы [ 2 ]

0 голосов
/ 16 января 2019

Прежде всего, cascade=ALL делает противоположное тому, что вы хотите. ALL=PERSIST,MERGE,REFRESH,DETACH,REMOVE, поэтому в основном говорится: «Когда я сохраняю, обновляю или удаляю Student, делаю то же самое со всеми связанными Courses», среди прочего.

Для @ManyToMany ассоциаций PERSIST, MERGE, REMOVE не имеют большого смысла. Возможно, вы захотите оставить REFRESH и DETACH, но вам бы посоветовали избавиться от остальных.

Во-вторых, удаление MERGE имеет побочный эффект получения TransientObjectException. Это происходит потому, что вы пытаетесь сохранить отдельную сущность, которая ссылается на другие отделенные сущности. Возможно, вы звоните repository.save(student), но это только объединяет сущность Student, и указанные сущности Course остаются отсоединенными.

Чтобы решить эту проблему, необходимо заменить экземпляры отсоединенного объекта на экземпляры управляемого объекта с теми же идентификаторами:

Set<Courses> managedCourses = new HashSet<>();
for (Course course : stud.getCourses()) {
    managedCourses.add(courseRepository.getOne(course.getId()));
}
stud.setCourses(managedCourses);
studentRepository.save(stud); //no TransientObjectException this time!

(обратите внимание на использование getOne() в цикле; у вас может возникнуть соблазн использовать findAllById(), думая, что это будет более производительным, но преимущество getOne() состоит в том, что он не получает связанное состояние объекта из источник данных. getOne() предоставляется JpaRepository специально для этого случая использования: для установления связей между сущностями)

Наконец, я вижу, что stud помечен @RequestBody, предполагая, что мы здесь в классе Controller. Чтобы вышеуказанный подход работал, вы хотите обернуть весь метод в транзакцию, используя @Transactional. Поскольку методы транзакционного контроллера не совсем хорошая практика, я бы предложил выделить тело метода studententry в отдельный аннотированный компонент @Transactional, @Service.

0 голосов
/ 15 января 2019

Вам нужно переключиться с @ManyToMany на @OneToMany.

Затем вы можете поставить каскад на Student и опустить его в сущностях StudentCourse и StudentCountry.

Единственным недостатком является то, что вам нужно создать промежуточные объекты для этих таблиц связи:

Student

@OneToMany(cascade = CascadeType.ALL, mappedBy="student")
private Set<StudentCourse> courses;

StudentCourse

@ManyToOne
private Student student;

@ManyToOne
private Course course;

Курс

@Entity
public class Course {
private String courseName;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int courseId;
@ManyToMany(mappedBy = "courses")
private List<StudentCourse> coursestudents;

Вам необходимо соответствующим образом изменить входящий объект json для поддержки этих промежуточных объектов ofc.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...