0

所以我有一个使用 JPA、Hibernate 和 Spring Data 的小型概念证明。在这个 POC 中,我创建了一个Post实体和一个Comment实体。该Post实体包含评论地图Map<Integer,Comment>

由于我使用实体列作为地图的键,因此我在将多个Comment实体持久化时遇到了问题。基本上,如果我没有明确设置Hibernate 的 id,就会将它们识别为同一个实体,并且只保留其中一个。MapComment@IdComment

我发现我可以Map通过指定垃圾键来持久化,一旦持久化,MySql 自动编号将替换它。这导致了一个问题,当前映射中的键不会接收commentId到数据库设置的新值。这导致我的单元测试失败。

所以基本上我有三个问题?

  1. 我应该指定垃圾键来持久化地图中的实体吗?
  2. 我的方法全错了吗?如果是这样,有什么更好的方法?
  3. 如果垃圾键没问题,插入后如何刷新它们?

Post.java

@Entity
@Table(name = "POST")
public class Post {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "POST_ID")
    private Integer postId;

    @Column(name = "TITLE")
    private String title;

    @OneToMany(mappedBy = "post", cascade = CascadeType.ALL)
    @MapKeyColumn(name="COMMENT_ID")
    private Map<Integer, Comment> comments = new HashMap<Integer, Comment>();

        /** Accessors (Get/Set) **/
        /** HashCode & Equals that does not consider the postId field or the Map */
}

评论.java

@Entity
@Table(name="COMMENT")
public class Comment {

    @Id
    @Column(name="COMMENT_ID")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer commentId;

    @Column(name="BODY")
    private String body;

    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="POST_ID")
    private Post post;

        /** Accessors (Get/Set) **/
        /** HashCode & Equals that does not consider the commentId field or the Post */
}

单元测试

@Test
public void insertTest2(){
    Comment comment = new Comment();
    Comment comment2 = new Comment();
    final String body1 = "This is a map test";
    final String body2 = "This is another map test";

    comment.setBody(body1);
    comment2.setBody(body2);

    Post post = new Post();
    post.setPostDate(new Date());
    post.setTitle("First Post");


    post.getComments().put(1,comment);   //Setting garbage IDs
    post.getComments().put(2, comment2); //Setting garbage IDs

    comment.setPost(post);
    comment2.setPost(post);

    repository.save(post);

    Post dbpost = repository.findOne(post.getPostId());

    Map<Integer, Comment> comments = dbpost.getComments();

    //Test fails using old id       
    assertTrue(comments.containsKey(comment.getCommentId()));
    //Same here 
    assertTrue(comments.containsKey(comment2.getCommentId()));  

}

另请注意,这是双向关系

4

1 回答 1

2

我应该指定垃圾键来持久化地图中的实体吗?

不会。一旦真实 ID 受到影响,地图就会处于不一致状态。地图的键应该是不可变的。

我的方法全错了吗?如果是这样,有什么更好的方法?

坦率地说,我真的不明白使用地图按 ID 保存评论的意义。实体管理器已经能够通过 ID 获得评论。我会简单地使用一个集合或一个列表。

另一种方法是在将评论添加到地图之前保留评论并刷新实体管理器,以确保它们已经具有真实 ID。

于 2013-04-05T18:29:40.667 回答