I want to save a relationship of two or more persons to each other with specific elements. A person with its skill and on a specific address should be connected to each other. Normaly I creat a table to save the ID's of each element and create a row in the table (in normal MySQL with PHP).
How do I solve this problem in Java Spring Boot (JPA-Hibernate-MySQL)?
When I create (or better ask for) an "object" (detached) from the repository of each element and want to save it in a new "repository" (database) then I got an error.
PartnerConnectionServiceImplementation (.java)
@Service
public class PartnerConnectionServiceImpl implements PartnerConnectionService {
@Autowired
private PartnerConnectionRepository partnerConnectionRepository;
@Autowired
private DanceSkillServiceImpl danceSkillDatabaseService;
@Autowired
private AddressLocationServiceImpl addressLocationDatabaseService;
@Autowired
private UserProfileServiceImpl userProfileDatabaseService;
@Override
public Optional<PartnerConnection> connectPartnersWithDanceSkillAndAddressLocation(long userIdPartner1, long danceSkillIdPartner1, long addressLocationIdPartner1, long userIdPartner2, long danceSkillIdPartner2, long addressLocationIdPartner2) {
Optional<UserProfile> userProfile1 = this.userProfileDatabaseService.getUserById(userIdPartner1);
Optional<UserProfile> userProfile2 = this.userProfileDatabaseService.getUserById(userIdPartner2);
Optional<DanceSkill> danceSkill1 = this.danceSkillDatabaseService.getDanceSkillById(danceSkillIdPartner1);
Optional<DanceSkill> danceSkill2 = this.danceSkillDatabaseService.getDanceSkillById(danceSkillIdPartner2);
Optional<AddressLocation> addressLocation1 = this.addressLocationDatabaseService.getAddressLocationById(addressLocationIdPartner1);
Optional<AddressLocation> addressLocation2 = this.addressLocationDatabaseService.getAddressLocationById(addressLocationIdPartner2);
if (
(userProfile1.isPresent()) && (userProfile2.isPresent())
){
Optional<PartnerConnection> theConnection = getPartnerConnectionOfPartners(
userProfile1.get(),
userProfile2.get());
if (theConnection.isPresent()) {
return theConnection;
}
}
if (
(userProfile1.isPresent()) && (userProfile2.isPresent()) &&
(danceSkill1.isPresent()) && (danceSkill2.isPresent()) &&
(addressLocation1.isPresent()) && (addressLocation2.isPresent())
) {
PartnerConnection newPartnerConnection = new PartnerConnection(
null,
userProfile1.get(),
danceSkill1.get(),
addressLocation1.get(),
userProfile2.get(),
danceSkill2.get(),
addressLocation2.get()
);
this.partnerConnectionRepository.save(newPartnerConnection);
return Optional.of(newPartnerConnection);
}
return Optional.empty();
}
...
PartnerConnection (.java)
// indicates the connecitons between partners/ users
@NoArgsConstructor
@AllArgsConstructor
@Data
@Entity
@Table(name = "partner_connection")
public class PartnerConnection {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@OneToOne(
fetch = FetchType.LAZY,
cascade = CascadeType.ALL
)
@JoinColumn(
name = "firstmessage_fk", // foreign key
nullable = true
)
private UserMessage firstMessage;
@ManyToOne(
fetch = FetchType.LAZY,
cascade = CascadeType.ALL
)
@JoinColumn(name = "onepartner_fk", // foreign key
nullable = false)
private UserProfile firstPartner;
@OneToOne(
fetch = FetchType.LAZY,
cascade = CascadeType.ALL
)
@JoinColumn(
name = "firstpartnerdanceskill_fk", // foreign key
nullable = false
)
private DanceSkill firstPartnerDanceSkill;
@OneToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
@JoinColumn(name = "firstpartneraddresslocation_fk", // foreign key
nullable = false)
private AddressLocation firstPartnerAddressLocation;
@ManyToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
@JoinColumn(name = "secondpartner_fk", // foreign key
nullable = false)
private UserProfile secondPartner;
@OneToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
@JoinColumn(name = "secondpartnerdanceskill_fk", // foreign key
nullable = false)
private DanceSkill secondPartnerDanceSkill;
@OneToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
@JoinColumn(name = "secondpartneraddresslocation_fk", // foreign key
nullable = false)
private AddressLocation secondPartnerAddressLocation;
public PartnerConnection(UserMessage firstMessage, UserProfile firstPartner, DanceSkill firstPartnerDanceSkill, AddressLocation firstPartnerAddressLocation, UserProfile secondPartner, DanceSkill secondPartnerDanceSkill, AddressLocation secondPartnerAddressLocation) {
this.firstMessage = firstMessage;
this.firstPartner = firstPartner;
this.firstPartnerDanceSkill = firstPartnerDanceSkill;
this.firstPartnerAddressLocation = firstPartnerAddressLocation;
this.secondPartner = secondPartner;
this.secondPartnerDanceSkill = secondPartnerDanceSkill;
this.secondPartnerAddressLocation = secondPartnerAddressLocation;
}
}
The error org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: ... nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: ...
appears on this.partnerConnectionRepository.save(newPartnerConnection);
Do you have any easy to understand suggestions?
I think your method should contain @Transactional annotation. You have marked all relationships as LAZY, so if you want to get them You need a transaction to load them into managed state from detached one then be able to attach it to the object you want to save