【问题标题】:JPA Collection Using Map使用地图的 JPA 集合
【发布时间】:2013-04-05 18:23:47
【问题描述】:

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

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

我发现我可以通过指定垃圾键来持久化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 */
}

Comment.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()));  

}

还要注意这是双向关系

【问题讨论】:

  • 为什么需要Map?为什么不是一个简单的List 评论?因为地图的键是实体的 id。或者这就是您的 POC 的全部意义所在?
  • @RodrigoSasaki 我的 POC 的重点是学习如何使用地图。这仅用于教育目的。

标签: java spring hibernate jpa spring-data


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 这只是一个 POC,它的全部意义在于学习如何使用地图。很抱歉,我应该在关于我不想偏离使用地图的方法的问题中指出。但是你说坚持 cmets 然后将它们添加到地图?呃,我害怕那个。
猜你喜欢
  • 2013-10-02
  • 2012-06-15
  • 2012-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多