冬眠,春天。同一实体的多种表示形式正在被合并

时间:2018-09-28 12:38:40

标签: java hibernate jpa

尝试更新实体列表(作业)时出现错误:

Multiple representations of the same entity [com.introlabsystems.upworkscraper.model.entities.Skill#42] are being merged. Detached: [Skill(id=42, skillName=Web Scraping)]; Detached: [Skill(id=42, skillName=Web Scraping)]

我认为是三个实体与Skill实体具有ManyToMany关系的情况。

@Entity
public class Job {

  @Id
  @Column(unique = true, nullable = false)
  @SerializedName(value = "ciphertext")
  private String id;
  @Column(length = 2048)
  private String title;
  @Column(columnDefinition = "TEXT")
  @JsonAdapter(value = DescriptionAdapter.class)
  private String description;
  @SerializedName(value = "subcategory2")
  private String category;

  @ManyToMany(cascade = {
      CascadeType.MERGE
  }, fetch = FetchType.EAGER)
  @JoinTable(
      joinColumns = {@JoinColumn(name = "job_id")},
      inverseJoinColumns = {@JoinColumn(name = "skill_id")}
  )
  @JsonAdapter(value = SkillsAdapter.class)
  private Set<Skill> skills;

  private String duration;
  private String engagement;
  @JsonAdapter(value = AmountAdapter.class)
  private String amount;
  @JsonAdapter(value = AmountAdapter.class)
  private String maxAmount;

  private String freelancersToHire;
  private String enterpriseJob;
  private String proposalsTier;
  private String stickyLabel;
  @SerializedName(value = "tierLabel")
  private String tier;

  @JsonAdapter(value = DateTimeAdapter.class)
  private LocalDateTime createdOn;
  @JsonAdapter(value = DateTimeAdapter.class)
  private LocalDateTime publishedOn;
  @JsonAdapter(value = DateTimeAdapter.class)
  private LocalDateTime renewedOn;
  private LocalDateTime hiredOn;

  @OneToOne(cascade = CascadeType.ALL)
  private Contract contract;

  @SerializedName(value = "type")
  @JsonAdapter(value = JobTypeAdapter.class)
  @Enumerated(value = EnumType.STRING)
  private JobType jobType;

  @Enumerated(value = EnumType.STRING)
  private JobStatus jobStatus = JobStatus.OPEN;

  private String projectStage;
  private String ongoingProject;
  private String projectType;
  private String finalOutput;
  private String Platform;
  private String oneTimeProject;
  private String jobSuccessScore;
  private String includeRisingTalent;
  private String englishLevel;
  private String upworkHours;
  private String freelancerType;
  private String preferredLocation;
  private String interviewing;

  @OneToOne(cascade = CascadeType.ALL)
  private PrivateStatus privateStatus;
}

@Data
@Entity
public class Skill {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private long id;
  private String skillName;
}

@Data
@Entity
public class Contract {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private long id;

  @JsonAdapter(value = ContractJobIdAdapter.class)
  @SerializedName(value = "jobInfo")
  private String jobId;

  private String totalCharge;
  private String totalHours;

  @JsonAdapter(value = AmountAdapter.class)
  private String rate;

  @JsonAdapter(value = DateTimeAdapter.class)
  private LocalDateTime startDate;
  @JsonAdapter(value = DateTimeAdapter.class)
  private LocalDateTime endDate;

  @ManyToOne(cascade = CascadeType.MERGE)
  @SerializedName(value = "contractorInfo")
  private Freelancer freelancer;

  @ManyToOne(cascade = CascadeType.ALL)
  private Client client;
}

@Data
@Entity
public class Freelancer {

  @Id
  @SerializedName(value = "ciphertext")
  private String id;
  @SerializedName(value = "contractorName")
  private String name;
  @Column(length = 2048)
  private String title;
  @Column(columnDefinition = "TEXT")
  @JsonAdapter(value = DescriptionAdapter.class)
  private String description;
  @JsonAdapter(value = FreelancerLocationAdapter.class)
  private String location;

  @ManyToMany(cascade = CascadeType.ALL)
  @JoinTable(
      joinColumns = {@JoinColumn(name = "freelancer_id")},
      inverseJoinColumns = {@JoinColumn(name = "skill_id")}
  )
  @JsonAdapter(value = SkillsAdapter.class)
  private Set<Skill> skills;

  private String hourlyRate;
  private String privateFeedbackHireAgain;
  private String rating;
  private String scores;
  private String totalEarnings;
  private String totalFeedback;
  private String totalFixedJobs;
  private String totalHourlyJobs;
  private String totalHours;
  private String totalJobsWorked;
  private String topRatedStatus;
  private String successScore;

  @OneToMany(cascade = CascadeType.ALL)
  private List<ContractHistory> contractHistories;

  @ManyToMany(cascade = {
      CascadeType.PERSIST,
      CascadeType.MERGE
  })
  @JoinTable(
      joinColumns = {@JoinColumn(name = "freelancer_id")},
      inverseJoinColumns = {@JoinColumn(name = "agency_id")}
  )
  private Set<Agency> agency;
}


@Data
@Entity
public class Agency {

  @Id
  @SerializedName(value = "chipertext")
  private String id;

  @JsonAdapter(value = AmountAdapter.class)
  private String minRate;
  @JsonAdapter(value = AmountAdapter.class)
  private String maxRate;
  private String city;
  private String country;
  @Column(columnDefinition = "TEXT")
  @JsonAdapter(value = DescriptionAdapter.class)
  private String description;
  private String jobSuccessScore;
  private String name;
  @Column(length = 2048)
  private String title;
  private String topRatedStatus;
  private String totalEarnings;
  private String totalHours;
  private String totalJobs;
  private String recentEarnings;
  private String averageRecentEarnings;
  @JsonAdapter(value = DateTimeAdapter.class)
  private LocalDateTime memberSince;

  @ManyToMany(cascade = CascadeType.ALL)
  @JoinTable(
      joinColumns = {@JoinColumn(name = "agency_id")},
      inverseJoinColumns = {@JoinColumn(name = "skill_id")}
  )
  @JsonAdapter(value = SkillsAdapter.class)
  private Set<Skill> skills;
}

我试图保存工作。在此之前,我从工作,代理,自由职业者那里获得了技能,试图在数据库中搜索这些技能并替换ID。

    for (Skill skill: skills) 
    {
        Skill skillWithID = 
        skillDataService.findBySkillName(skill.getSkillName())
          .orElseGet(() -> skillDataService.save(skill));
        skill.setId(skillWithID.getId());
    }

2 个答案:

答案 0 :(得分:1)

已更改

CascadeType.MERGE

CascadeType.PERSIST,
CascadeType.DETACH,
CascadeType.REFRESH,
CascadeType.REMOVE

它有效

答案 1 :(得分:0)

您面临这个问题是因为您正在将对象添加到已经可用的列表中。同时使用 oneToMany 映射执行保存操作

现在从级联中删除 CascadeType.MERGE 是一种解决方案,但不是最好的解决方案,因为从级联中删除 MERGE 后,您将永远无法更新映射对象

如果您还想对映射对象执行更新操作和保存操作,那么在将映射对象添加到列表/集合之前,只需在列表中检查/搜索对象,如果映射对象在列表中可用,则执行操作在那个特定的对象上。

check my other post for example