Reputation: 954
I read https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/. I tried suggestion config like(using spring data JPA,hibernate 5.0 as vendor ):
public class PaperSubjectType{
@Id
private Long id;
@OneToOne(fetch = FetchType.LAZY)
@MapsId
private PaperSetting paperSetting;
..
}
class PaperSetting{
@Id
@GeneratedValue
private Long id;
..
}
first I tried the example:
PaperSetting paperSettingInDb = paperSettingRepository.findOne(1);
PaperSubjectType paperSubjectType = new PaperSubjectType();
paperSubjectType.setSubjectCode("91");
paperSubjectType.setPaperSetting(paperSettingInDb);
paperSubjectTypeRepository.save(paperSubjectType);
error:detached entity passed to persist:PaperSetting. it seems hibernate take PaperSetting as detached when cascade
2 if I want to create both PaperSubjectType and PaperSetting together,do I need to do this:
PaperSetting paperSetting = new PaperSetting();
paperSetting.setxx;
PaperSetting paperSettingInDbNew = paperSettingRepository.save(paperSetting);
PaperSubjectType paperSubjectType = new PaperSubjectType();
paperSubjectType.setPaperSetting(paperSettingInDbNew);
paperSubjectTypeRepository.save(paperSubjectType);
or I should use bidirectional in this situation? thank you!
Upvotes: 14
Views: 6569
Reputation: 1
The reason is because the entity is in detached state. How does that happen? You pass the entity that is not in persistent state - meaning it is not associated with a persistent context. So one of the solutions would be:
PaperSetting paperSetting = new PaperSetting();
paperSetting.setxx;
PaperSubjectType paperSubjectType = new PaperSubjectType();
// we create PaperSetting entity and we pass it before saving it,
// as it will bedetached from the persistent context as soon as we save it
paperSubjectType.setPaperSetting(paperSetting);
paperSubjectTypeRepository.save(paperSubjectType);
Upvotes: 0
Reputation: 26502
1) Add cascading option:
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@MapsId
private PaperSetting paperSetting;
2) Having that in place, you can save only PaperSubjectType while creating both entities anew:
PaperSetting paperSetting = new PaperSetting();
paperSetting.setxx;
PaperSubjectType paperSubjectType = new PaperSubjectType();
paperSubjectType.setPaperSetting(paperSettingInDbNew);
paperSubjectTypeRepository.save(paperSubjectType);
Upvotes: 0
Reputation: 153710
I tried it Hibernate 5.2 and it works like a charm.
Assuming you have these entities:
@Entity(name = "Person")
public static class Person {
@Id
@GeneratedValue
private Long id;
@NaturalId
private String registrationNumber;
public Person() {}
public Person(String registrationNumber) {
this.registrationNumber = registrationNumber;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRegistrationNumber() {
return registrationNumber;
}
}
@Entity(name = "PersonDetails")
public static class PersonDetails {
@Id
private Long id;
private String nickName;
@OneToOne
@MapsId
private Person person;
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
And this data access logic:
Person _person = doInJPA( this::entityManagerFactory, entityManager -> {
Person person = new Person( "ABC-123" );
entityManager.persist( person );
return person;
} );
doInJPA( this::entityManagerFactory, entityManager -> {
Person person = entityManager.find( Person.class, _person.getId() );
PersonDetails personDetails = new PersonDetails();
personDetails.setNickName( "John Doe" );
personDetails.setPerson( person );
entityManager.persist( personDetails );
} );
The test passes just fine in Hibernate ORM.
Maybe it was a bug in 5.0 that got fixed, so you are better of upgrading.
Upvotes: 1
Reputation: 4532
I think you may have forgotten to wrap the logic in a @Transactional block
@Transactional
PaperSetting paperSettingInDb = paperSettingRepository.findOne(1);
PaperSubjectType paperSubjectType = new PaperSubjectType();
paperSubjectType.setSubjectCode("91");
paperSubjectType.setPaperSetting(paperSettingInDb);
paperSubjectTypeRepository.save(paperSubjectType);
without that crudRepository.findOne()
will open it's own short lived transaction so when you get the return of findOne() the entity is already detached, hence the error
Upvotes: 2