获取ManyToMany映射表的id

时间:2017-08-07 14:00:51

标签: java spring hibernate jpa many-to-many

我正在使用Spring Boot和Hibernate编写API,其中我的持久化实体对象也用作发送到客户端和从客户端发送的DTO。这是我使用的典型实体的简化版本:

@Entity
@Table(name = "STUDENT")
public class Student {
    @Id
    @GeneratedValue
    @Column(name = "ID")
    private Long id;

    @ElementCollection
    @CollectionTable(name = "GROUP_STUDENT",
                     joinColumns = @JoinColumn(name = "GROUP_ID"))
    @Column(name="STUDENT_ID")
    private Set<Long> groupIds;

    @JsonIgnore
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name="GROUP_STUDENT",
               joinColumns = @JoinColumn(name="GROUP_ID"),
               inverseJoinColumns = @JoinColumn(name="STUDENT_ID")
    )
    private Set<Group> groups = new HashSet<>();

    // getters and setters
}

这是关联的类:

@Entity
@Table(name = "GROUP")
public class Group {
    @Id
    @GeneratedValue
    @Column(name = "ID")
    private Long id;

    @JsonIgnore
    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "groups")
    private Set<Student> students = new HashSet<>();

    // getters and setters
}

如您所见,@ManyToManyStudent之间存在Group关联。

由于我将这些对象发送到客户端,因此我选择仅发送关联的id而不是关联本身。我已使用this answer解决了这个问题,并且按预期工作。

问题是这个。当hibernate尝试持久化Student对象时,它会按预期插入groups,但它也会尝试将groupIds插入到映射表GROUP_STUDENT中。由于映射表复合id的唯一约束,这当然会失败。并且不可能将groupIds标记为insertable = false,因为它是@ElementCollection。而且我不认为我可以使用@Formula,因为我需要Set而不是减值。

这当然可以通过在保存或持久保存这样一个实体之前总是清空groups的{​​{1}}来解决,但这非常危险且容易忘记。

所以我想要的基本上是groupIds类中的只读groupIds,它从Student映射表加载数据。这可能吗?我很感激任何建议,如果看起来不清楚,我很乐意就此提出问题。

1 个答案:

答案 0 :(得分:1)

我设法通过制作id-collection @Transient并使用@PostLoad填充它来解决这个问题:

@Entity
@Table(name = "STUDENT")
public class Student {
    @PostLoad
    private void postLoad() {
        groupIds = groups.stream().map(Group::getId).collect(Collectors.toSet());
    }

    @Id
    @GeneratedValue
    @Column(name = "ID")
    private Long id;

    @Transient
    private Set<Long> groupIds;

    @JsonIgnore
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name="GROUP_STUDENT",
               joinColumns = @JoinColumn(name="GROUP_ID"),
               inverseJoinColumns = @JoinColumn(name="STUDENT_ID")
    )
    private Set<Group> groups = new HashSet<>();

    // getters and setters
}