所以我使用JPA,Hibernate和Spring Data进行了一个小概念验证。在这个POC中,我创建了一个Post
实体和一个Comment
实体。 Post
实体包含评论地图Map<Integer,Comment>
。
由于我使用Comment
实体Map
列作为地图的关键字,因此我遇到了将多个Comment
实体持久存储到@Id
的问题。基本上,如果我没有明确设置Comment
Hibernate的id将它们识别为同一个实体并且只保留其中一个。
我发现我可以通过指定垃圾密钥来持久化Map
,MySql自动编号会在持久化后替换。这导致了一个问题,当前映射中的键不会收到数据库设置的新commentId
值。这导致我的单元测试失败。
所以基本上我有三个问题?
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()));
}
另请注意,这是一种双向关系
答案 0 :(得分:2)
我应该指定垃圾密钥来保存地图中的实体吗?
没有。一旦真实ID受到影响,地图就会处于不一致状态。地图的键应该是不可变的。
我的方法都错了吗?如果是这样,最好的方法是什么?
坦率地说,我并没有真正看到使用地图按ID保存评论的重点。实体经理已经能够通过ID获得评论。我只想使用Set或List。
另一种方法是在将注释添加到地图之前保留注释并刷新实体管理器,以确保它们已经具有真实ID。