Следующий код будет работать нормально:
public class Child {
@Id
@Column(name = "code", insertable = false, updatable = false)
String code;
@MapsId
@JoinColumn(name = "code")
@OneToOne
Parent parent;
}
и тест
@Test
@Transactional
public void testSpringDataJpaRepository() {
Parent pA = parentRepo.save(Parent.builder().code("A").build());
Child child = Child.builder().parent(pA).build();
childRepo.save(child);
}
Объяснить:
Посмотрите на реализацию SimpleJpaRepository.save
@Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
Чем чек AbstractEntityInformation.isNew
.
Делается вывод, что сущность является новой только в том случае, если она равна нулю (или 0 для числовых типов).
Следовательно, ваш childRepo.save(child);
эквивалентен entityManager.merge(child);
Убедитесь, что при вызове слияния во втором тесте ошибка, которую вы получаете, идентична.
Для решения проблемы:
- не устанавливайте значение для вашего ребенка
@Id
(возможно, вы хотите, чтобы lombok также не генерировал для него сеттер). Это приведет к разрешению persist
вместо merge
- обратите внимание, что у вас есть 2 поля
code
и parent
, сопоставленные одному столбцу БД. Чтобы сделать сопоставление правильным, я использовал принудительный insertable = false, updatable = false
для столбца @Id
(изменение поля parent
приведет к созданию правильного sql)