我遇到了问题,需要您的帮助才能解决这个问题。希望这一点可能成为类似问题的参考......
在我最小化的商业模式中,有用户和标题。应首先创建标题,并将其分配给许多用户,并且用户可以共享相同的标题。因此,我使用@ManyToMany关系创建了两个名为User和Title的实体,并确定Title应该拥有此关系。另外,我有一个UnitTest来运行这个例子。
用户实体
public class User {
Long id;
String name;
Set<Title> titles = new HashSet<Title>();
@Id
@GeneratedValue
@Column(name = "id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/*============ Approach1 ============*/
// @ManyToMany(mappedBy = "users")
/*============ Approach2 ============*/
// @ManyToMany
/*============ Approach3 ============*/
@ManyToMany
@JoinTable( name = "tb_title_user",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "title_id"))
public Set<Title> getTitles() {
return titles;
}
public void setTitles(Set<Title> titles) {
this.titles = titles;
}
}
标题实体
public class Title {
Long id;
String description;
Set<User> users = new HashSet<User>();
@Id
@GeneratedValue
@Column(name = "id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "description")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
/*============ Approach1 & Approach2 & Approach3 ============*/
@ManyToMany
@JoinTable( name = "tb_title_user",
joinColumns = @JoinColumn(name = "title_id"),
inverseJoinColumns = @JoinColumn(name = "user_id"))
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
}
单元测试
public class UserTest {
@Autowired
private SessionFactory sessionFactory;
@Test
@Rollback(false)
@Transactional
public void saveUser(){
Session session = sessionFactory.getCurrentSession();
String now = new Date().toString();
Title title = new Title();
title.setDescription("TitleDescription: " + now);
session.save(title);
User user = new User();
user.setName("UserName: " + now);
user.getTitles().add(title);
session.saveOrUpdate(user);
}
}
如果你看一下上面的代码,你会看到三种不同的方法。下面描述了数据是否正确存储在数据库表中:
Title User JoinTable
Approach1 Yes Yes No
Approach2 Yes Yes Yes
Approach3 Yes Yes Yes
以下是我对每种方法的看法:
Approach1
根据Hibernate文档(http://docs.jboss.org/hibernate/core/4.1/manual/en-US/html/ch07.html#d5e5537),我应该遵循Approach1。特别是,因为文档明确提到:
“如前所述,对方不必(绝不)描述 物理映射:包含所有者的简单mappedBy参数 边属性名绑定两个。“
如果我理解正确,我不必(不得)在用户实体中添加@JoinTable。
Approach2
它有效,但它忽略了我的@JoinTable定义并创建了自己的表:tb_user_tb_title
。它闻起来很腥。
Approach3
它有效,但文档说不要使用它。因此,在我看来,我可能会后悔在企业产品中使用这种方法。
答案 0 :(得分:4)
唯一正确的方法是第一个:
@ManyToMany(mappedBy = "users")
public Set<Title> getTitles() {
return titles;
}
...
@ManyToMany
@JoinTable(name = "tb_title_user",
joinColumns = @JoinColumn(name = "title_id"),
inverseJoinColumns = @JoinColumn(name = "user_id"))
public Set<User> getUsers() {
return users;
}
反面使用mappedBy
属性来说:“我是反面。去看看目标实体中的users
属性,看看这个关联是如何映射的。”
你做错了是你只修改测试中的反面。 JPA / Hibernate只考虑所有者方知道是否存在关联。所以不要做
user.getTitles().add(title);
你应该做
title.getUsers().add(user);
甚至更好,两者都做,以确保对象图是连贯的。
我真的希望这个问题成为类似问题的参考,但我对此表示怀疑,因为我已经回答了这个问题了很多次,并且它一再出现,尽管文档中已经清楚地解释了这一点:
如果关联是双向的,则一方必须是所有者,一方必须是反向结束(即,在更新关联表中的关系值时将忽略它):
[在双向多对多关联的每一侧都有适当的注释示例]