我有一个模型多次与其他两个实体建立多对多关系,当我尝试保存它们时出现堆栈溢出错误。尝试了一堆解决方案,阅读了一堆文章,甚至在这里找到了答案,但都没有奏效。由于他们中的很多人真的很老,所以我决定发布这个问题。
我的关系是“Profile”有多个“Stat”和多个“Interest”,所以一个 Profile 可以有多个 Stats,一个 Stat 可以在多个 Profiles 中,因此一个 Profile 可以有多个 Interests,一个 Interest 可以在多个 Profiles .基于此,我创建了类“ProfileStat”和“ProfileInterest”,它们分别将“ProfileStatId”和“ProfileInterestId”作为 IDClass,如下所示: 简介类
@Entity
public class Profile extends GenericEntity {
@Column(nullable = false, length = 100)
private String name;
@OneToOne(mappedBy = "stat", cascade = CascadeType.ALL, orphanRemoval = true)
private ProfileStat smokes;
@OneToMany(mappedBy = "stat", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<ProfileStat> languages;
@OneToMany(mappedBy = "interest", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<ProfileInterest> relationshipInterests;
}
ProfileStat 类
@Entity
public class ProfileStat {
@EmbeddedId
private ProfileStatId profileStatId = new ProfileStatId();
@ManyToOne
@MapsId("statId")
@JoinColumn(name = "stat_id")
private Stat stat;
@ManyToOne
@MapsId("profileId")
@JoinColumn(name = "profile_id")
private Profile profile;
@Column
private boolean displayable;
}
ProfileStatId 类
@Embeddable
public class ProfileStatId implements Serializable {
private static final long serialVersionUID = 1L;
private UUID statId;
private UUID profileId;
}
简介兴趣班
@Entity
public class ProfileInterest {
@EmbeddedId
private ProfileInterestId profileInterestId = new ProfileInterestId();
@ManyToOne
@MapsId("interestId")
@JoinColumn(name = "interest_id")
private Interest interest;
@ManyToOne
@MapsId("profileId")
@JoinColumn(name = "profile_id")
private Profile profile;
@Column
private boolean displayable;
}
ProfileInterestId 类
@Embeddable
public class ProfileInterestId implements Serializable {
private static final long serialVersionUID = 1L;
private UUID interestId;
private UUID profileId;
}
在那之后,我有一个端点成功保存了没有统计和兴趣的配置文件,但是,当我尝试保存统计和兴趣时,它给了我一个堆栈溢出异常。我保存配置文件,然后立即创建 Stats 和 Interests 实例,但它甚至无法完成对象的创建,更不用说保存它们了。创建这些对象的方法如下所述:
public Profile enrichProfile(Profile profile, ProfileDTO profileDTO) throws RestRequestException {
// There's some code here that works, the problem is with the next line
profile.setLanguages(buildProfileStat(findStats(profileDTO.getLanguages()), profile));
profile.setRelationshipInterests(buildProfileInterest(findInterests(profileDTO.getRelationshipInterestsId()), profile));
return profile;
}
private Set<ProfileStat> buildProfileStat(Collection<Stat> stats, Profile profile) {
Set<ProfileStat> profileStats = new HashSet<>();
for(Stat stat : stats) {
profileStats.add(new ProfileStat(stat, profile, false));
}
return profileStats;
}
private Set<Stat> findStats(Collection<UUID> ids) throws RestRequestException {
Set<Stat> stats = new HashSet<>();
for (UUID id : ids) {
stats.add(statService.findById(id)
.orElseThrow(() -> new RestRequestException(HttpStatus.NOT_FOUND, ErrorIndicator.ERROR_CPRAPI_0012_D.getMessage())));
}
return stats;
}
private Set<ProfileInterest> buildProfileInterest(Collection<Interest> interests, Profile profile) {
Set<ProfileInterest> profileInterest = new HashSet<>();
for(Interest interest : interests) {
profileInterest.add(new ProfileInterest(interest, profile, false));
}
return profileInterest;
}
private Set<Interest> findInterests(Collection<UUID> ids) throws RestRequestException {
Set<Interest> interests = new HashSet<>();
for (UUID id : ids) {
interests.add(interestService.findById(id)
.orElseThrow(() -> new RestRequestException(HttpStatus.NOT_FOUND, ErrorIndicator.ERROR_CPRAPI_0012_E.getMessage())));
}
return interests;
}
这就是我在 Profile 实体上执行“repository.save()”之后立即调用创建统计信息和兴趣的方法的方式:
@ApiOperation("Endpoint to register/save a new profile.")
@PostMapping(value = "/save")
public Profile saveProfile(@RequestBody ProfileDTO profileDTO) throws RestRequestException, CouplerPlanLimitationException {
profileService.verifyUserCanSaveProfile(profileDTO.getUserId());
Profile profile = profileService.save(profileFactory.newProfileDtoToProfile(profileDTO));
profile = profileFactory.enrichProfile(profile, profileDTO);
return profile;
}
很抱歉发了这么长的帖子,但我不能比这个更能减少问题,而且仍然有一个可重现和易于理解的代码可以分享。
我用this解决了这个问题。我用一个简单的例子构建了一个 Github 存储库。
我填充对象的方法保存它但具有不同的结构:
private Set<ProfileStat> buildProfileStat(Collection<Stat> stats, Profile profile) {
Set<ProfileStat> profileStats = new HashSet<>();
for(Stat stat : stats) {
ProfileStatId profileStatId = new ProfileStatId(stat.getId(), profile.getId());
ProfileStat profileStat = new ProfileStat(profileStatId, fals e);
profileStat.setProfile(profile);
profileStat.setStat(stat);
profileStats.add(profileStatService.save(profileStat));
}
return profileStats;
}
private Set<ProfileInterest> buildProfileInterest(Collection<Interest> interests, Profile profile) {
Set<ProfileInterest> profileInterests = new HashSet<>();
for(Interest interest : interests) {
ProfileInterestId profileInterestId = new ProfileInterestId(interest.getId(), profile.getId());
ProfileInterest profileInterest = new ProfileInterest(profileInterestId, false);
profileInterest.setProfile(profile);
profileInterest.setInterest(interest);
profileInterests.add(profileInterestService.save(profileInterest));
}
return profileInterests;
}
我必须在
ProfileStat
实体上添加一个构造函数,它接受 ID 类和额外的列但不需要对象;您稍后会添加它们。不知道能不能加一下
我还必须更改填充“配置文件”的方式,从
profile.setLanguages(buildProfileStat(findStats(profileDTO.getLanguages()), profile));
到 buildProfileStat(findStats(profileDTO.getLanguages()), profile);
.
我无法将保存的列表设置回它的主要对象实例,Profile;它抛出 Stackoverflow 异常。可能有一些解决方法。