#hibernate #spring-boot #jpa
#переход в спящий режим #весенняя загрузка #jpa
Вопрос:
Я пытаюсь сгенерировать множество Team
объектов, каждый из которых состоит из нескольких Person
объектов, используя JPA. Я знаю, что мне нужно вручную обновить обе стороны отношения «многие ко многим», поэтому это то, что я пытаюсь сделать.
Вот Person.java
(для краткости опущены геттеры и установщики).
/**
* Represents any person (teaching assistant, student, or other) that exists in this application.
*/
@Entity
@Table(name = "people")
@Inheritance(
strategy = InheritanceType.JOINED
)
public abstract class Person extends BasicEntity {
@Column(nullable = false)
private String firstName;
@Column(nullable = false)
private String lastName;
@Column
private String emailAddress;
/**
* The list of teams that this person belongs to.
*/
@ManyToMany(
cascade = CascadeType.ALL,
fetch = FetchType.LAZY
)
@JoinTable(
name = "team_members",
joinColumns = @JoinColumn(name = "person_id"),
inverseJoinColumns = @JoinColumn(name = "team_id")
)
private List<Team> teams;
/**
* Default constructor for JPA.
*/
protected Person () {
this.teams = new ArrayList<>();
}
/**
* Constructs a new Person.
* @param firstName The person's first name.
* @param lastName The person's last name.
* @param emailAddress The person's email address.
*/
public Person(String firstName, String lastName, String emailAddress) {
this();
this.firstName = firstName;
this.lastName = lastName;
this.emailAddress = emailAddress;
}
public void assignToTeam(Team team) {
this.teams.add(team);
//team.addMember(this);
}
Как вы можете видеть, в assignToTeam
методе я закомментировал «рефлексивную» часть, где я обновляю Team
представление отношения после обновления Person
собственного.
Поскольку это необходимо для решения этой проблемы, вот Team.java
.
/**
* A group consisting of one or more members. Child classes should define P as a sub class of Person to define custom
* behavior if needed.
* @param <P> The type of members this group contains.
*/
@Entity
@Inheritance(
strategy = InheritanceType.JOINED
)
public abstract class Team<P extends Person> extends BasicEntity {
/**
* The list of members in this group.
*/
@ManyToMany(
cascade = CascadeType.ALL
)
@JoinTable(
name = "team_members",
joinColumns = @JoinColumn(name = "team_id"),
inverseJoinColumns = @JoinColumn(name = "person_id")
)
protected List<P> members;
/**
* The course that this team belongs to.
*/
@ManyToOne(
optional = false
)
private Course course;
/**
* Default constructor for JPA and initializing list of members for any child classes.
*/
protected Team() {
this.members = new ArrayList<>();
}
public void addMember(P person) {
if (!this.containsMember(person)) {
this.members.add(person);
}
}
Проблема возникает, когда я генерирую набор тестовых данных для своего приложения, и я вызываю следующий метод:
private List<StudentTeam> generateStudentTeams() {
StudentGenerator studentGenerator = new StudentGenerator(this.getSeed());
List<StudentTeam> teams = new ArrayList<>(this.studentGroupCount);
for (int i = 0; i < this.studentGroupCount; i ) {
StudentTeam team = new StudentTeam();
List<Student> students = studentGenerator.generateList(this.studentGroupSize);
for (Student s : students) {
s.assignToTeam(team);
}
teams.add(team);
}
return teams;
}
что приводит к некоторым ошибкам следующего характера:
Caused by: org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [private nl.andrewlalis.teaching_assistant_assistant.model.people.TeachingAssistantRole nl.andrewlalis.teaching_assistant_assistant.model.people.TeachingAssistant.role] by reflection for persistent property [nl.andrewlalis.teaching_assistant_assistant.model.people.TeachingAssistant#role] : nl.andrewlalis.teaching_assistant_assistant.model.people.Student@1028bf36
Мой вопрос в том, как я могу правильно установить обе стороны отношения и избежать такой проблемы?
Комментарии:
1. Существует несколько причин для исключения PropertyAccessException. Вы пробовали комментировать атрибут пользователя «teams» только с помощью @ManyToMany (mappedBy = «members»)? Правильно ли сгенерированы таблицы с использованием внешних ключей?
2. @DiegoVictordeJesus Да, я проверил, что все таблицы сгенерированы точно так, как предполагалось, с использованием внешних ключей и так далее. Я даже протестировал создание отдельных объектов в этом вопросе, все из которых работают должным образом.
Ответ №1:
Если вы решите отобразить связь в обоих направлениях, то одно направление должно быть определено как владелец, а другое должно использовать атрибут mappedBy для определения его сопоставления. Это также позволяет избежать необходимости дублировать информацию о объединяемой таблице в обоих местах.
Если mappedBy не используется, то поставщик сохраняемости предположит, что существуют две независимые взаимосвязи, и в конечном итоге вы получите повторяющиеся строки, вставленные в таблицу объединения. Если у вас концептуальная двунаправленная связь, но в базе данных есть две разные таблицы объединения, то вы не должны использовать mappedBy, поскольку вам необходимо поддерживать две независимые таблицы.
https://en.wikibooks.org/wiki/Java_Persistence/ManyToMany#Bi-directional_Many_to_Many