0

I have 3 entities: job, schedule and groups, the relationship between them are: schedule has multiple groups, and multiple jobs; job has multiple groups, which may or may not get from the schedule it related to

when I created a schedule, i specified its groups, then i created a job, whose schedule is the one just created, and the job's group is the groups from that schedule, and then I got this error message of "detached entity passed to persist". I tried to update the cascade type to all kind of combination but still won't work. please help.

here is my code:

@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "groups")
public class Group {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Column(name = "group_guid", nullable = false, unique = true)
    private String groupId;
}

@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "schedules")
public class Schedule {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    ....
    @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
    @JoinTable(name = "schedules_to_groups",
            joinColumns = @JoinColumn(name = "schedule_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name="group_id", referencedColumnName = "id"))
    private List<Group> groups;

     @OneToMany(mappedBy = "schedule", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private Set<Job> job;

....

@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "jobs")
public class Job {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "jobs_to_groups",
            joinColumns = @JoinColumn(name = "job_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name="group_id", referencedColumnName = "id"))
    private List<Group> groups;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "schedule_fk")
    private Schedule schedule;

the code to create job:

List<Schedule> scheduleList = scheduleRepository.findAll();
 for (Schedule schedule : scheduleList) {
            Job job = new Job();
            job.setSchedule(schedule);
            job.setGroups(schedule.getGroups());  <--- get it from schedule
            jobRepository.save(job);
...
}

error message i got:

org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: com.xxx.Group

I tried to remove 'cascade = CascadeType.ALL' from Job class, the above code pass , however the following code failed:

    Group group6 = new Group();
    group6.setGroupId("group6");

    Job job = new Job();
    job.setGroups(Lists.newArrayList(group6));
    jobRepository.save(job);  <--- failed here

the error message is:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.xxx.ReportGroup

Last I tried 'cascade = CascadeType.MERGE' in Job on groups field, i saw an even strange behavior, originally schedule has 3 groups, after the following code, the relationship between schedule and 3 groups was removed, instead job has relationship with those 3 groups, but what I expect is both schedule and job have those 3 groups.

List<Schedule> scheduleList = scheduleRepository.findAll();
     for (Schedule schedule : scheduleList) {
                Job job = new Job();
                job.setSchedule(schedule);
                job.setGroups(schedule.getGroups());  <--- get it from schedule
                jobRepository.save(job);
    ...
    }

when I checked the log, i found this :

Hibernate: 
    delete 
    from
        `schedules_to_groups` 
    where
        schedule_id=?
Hibernate: 
    insert 
    into
        `
        jobs_to_groups` (
            job_id, group_id
        ) 
    values
        (?, ?)

so hibernate deleted the relationship between schedule and groups right before it insert job and its groups, but why?

user468587
  • 4,799
  • 24
  • 67
  • 124
  • can u try adding @transactional to the service layer of your code ? – user641887 Oct 11 '17 at 20:12
  • does the detailed error state the entity/class that is detached when saving ? – pirho Oct 11 '17 at 20:41
  • @pirho it complaint about Group entity – user468587 Oct 11 '17 at 21:12
  • Without `CascadeType.PERSIST (or .ALL)` you need to manually save all new objects added to the entity to be saved. That is why the latter error occurs. The first error usually is related to a problem where entity - in this case `Group` - is not managed in the same context where the save is atttempted. Do you create groups and set `group.id` manually in `schedule.getGroups()` or does it fetch groups from db as managed entities? – pirho Oct 12 '17 at 06:24
  • just realized that you have the `@Getter` & `@Setter` annotations there and that you most propably use default getters/setters so my previous question was not valid. So better ask how is `scheduleRepository` managed ? – pirho Oct 12 '17 at 07:26
  • did you try `CascadeType.MERGE` instead of `CascadeType.ALL`? – Atimene Nazim Oct 12 '17 at 07:43
  • @pirho I don't manually set group id, the group is created and added to schedule, when I saved schedule to repository, the groups was saved to repository too since I specify CascadeType.ALL on Scheduler's groups field. – user468587 Oct 13 '17 at 05:12
  • @AtimeneNazim, i tried CascadeType.MERGE too, but even strange thing happened, i've updated my post on that. – user468587 Oct 13 '17 at 05:29
  • 1
    did you already see this: [JPA/Hibernate: detached entity passed to persist](https://stackoverflow.com/questions/13370221/jpa-hibernate-detached-entity-passed-to-persist) might be the same problem – pirho Oct 13 '17 at 06:31
  • @pirho, thanks for the link, i eventually dropped the CascadeType stuff, manually maintain the consistency myself, it's easy that way. those CascadeType is too unpredictable. – user468587 Oct 17 '17 at 18:07

0 Answers0