2017-08-07 64 views
1

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

@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 
} 

正如你所看到的,有StudentGroup之间的@ManyToMany关联。

因为我发送这样的对象给客户端,所以我选择只发送关联的id而不发送关联本身。我已经使用this answer解决了这个问题,它按预期工作。

问题是这样的。当hibernate尝试保留Student对象时,它会按预期插入groups,但它也会尝试将groupIds插入到映射表GROUP_STUDENT中。这当然会失败,因为映射表组合标识的唯一约束。并且不可能将groupIds标记为insertable = false,因为它是@ElementCollection。而且我不认为我可以使用@Formula,因为我需要Set而不是降价。

这当然可以通过在保存或坚持这样一个实体之前始终清空groupIdsgroups来解决,但这是非常危险且容易忘记的。

所以我想要的是Student类中的只读groupIds,它加载了GROUP_STUDENT映射表中的数据。这可能吗?我很感激任何建议,并且很高兴在这个问题上精心研究这个问题是否看起来不清楚。

回答

1

我已经设法通过将ID收集@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 
}