У меня есть таблица базы данных. Например, T_STUDENTS
, поверх которой я должен создать объект JPA. Все три столбца в таблице: NON NULL
, а в таблице есть собственная ссылка: mentor_id
id | name | mentor_id
-----|---------|----------
1 | John | 1
-----|---------|----------
2 | Marc | 1
-----|---------|----------
3 | Abby | 2
-----|---------|----------
4 | Jimy | 3
-----|---------|----------
5 | Boni | 4
-----|---------|----------
. У каждого ученика есть наставник, который также является учеником. Между учеником и наставником существуют строгие отношения OneToOne. Для идентификатора 1 не может быть никакого наставника, поэтому у него есть идентификатор наставника, так как он id
. Идентификаторы генерируются с использованием последовательности базы данных.
Проблема заключается в том, что при создании первой записи с идентификатором 1 hibernate не назначает тот же идентификатор, что и идентификатор наставника, даже если я создал необходимые отношения. Поскольку столбцы не могут быть нулевыми, а hibernate не назначает mentor_id, генерируется ненулевое исключение SQLConstraint.
Ниже описано, как я создал отношение.
@Entity
@Table(name = 'T_STUDENTS')
public class Student implements Serializable {
@Id
@SequenceGenerator(name = 'S_STUDENTS_SEQUENCE', allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = 'S_STUDENTS_SEQUENCE')
@Column(name = "id")
private Long studentId;
@Column(name = "name", length = 20)
private String studentName;
@OneToOne(optional = false, cascade = CascadeType.NONE)
@JoinColumn(name = "mentor_id")
private Student mentor;
// getters and setters
}
Я установил CascadeType.NONE
потому что иначе hibernate пытается извлечь 2 идентификатора из последовательности и пытается создать 2 записи, которые не желательны.
Проблема в том, как я могу вставить самую первую запись. Ниже описывается, как выполняется вставка.
Student student = Student.builder()
.setName('John')
.build();
student = student.toBuilder().setMentor(student).build();
return studentRepository.save(student);
Если я поменяю аннотацию отношений на @ManyToOne
, поскольку технически значение mentor_id равно 1, сопоставлено 2 студентам, я получаю следующее исключение
.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation
Редактировать 1 : Если тип отношения изменен на @ManyToOne и удален каскад, появляется следующая ошибка:
org.hibernate.action.internal.UnresolvedEntityInsertActions.logCannotResolveNonNullableTransientDependencies - HHH000437: Attempting to save one or more entities that have a non-nullable association with an unsaved transient entity. The unsaved transient entity must be saved in an operation prior to saving these dependent entities.
Редактировать 2: Изменен тип каскада to cascade = CascadeType.PERSIST
и hibernate пытается сохранить наставника в виде отдельной записи. Я проверил из журналов, что он пытается получить 2 разных идентификатора последовательности и создает 2 запроса на вставку, оба значения mentor_id равны нулю.