休眠多对多级联保存连接表

问题描述:

所以这里是我想要完成的,如果它是所有可能的话。 我正在尝试使用级联将以下对象保存在数据库中。休眠多对多级联保存连接表

这是我遇到的问题的简单示例。我看到它的工作方式是,hibernate应该按顺序插入“用户”,然后是“组”,然后是“用户组”,但是发生的是插入“用户”和“用户组”,这导致“对象引用未保存的瞬态实例“错误在下面的日志中的组。

很明显,用自己的save()调用保存单个对象是可行的,但真正的数据库比这个大得多,我宁愿避免这种情况。

下面的“TestCode”复制了数据是如何传给我的,它将从JSON数据中反序列化。

我怀疑它与我的映射有关,但我无法确定原因。

仅供参考我正在使用Hibernate 5.2.10.Final。

那么我错过了什么?

DB Diagram

User.java

@Entity 
@Table(name = "User") 
public class User implements java.io.Serializable { 

private static final long serialVersionUID = -7899020279254796671L; 

@Id 
@GeneratedValue(strategy = GenerationType.IDENTITY) 
@Column(name = "userID", unique = true, nullable = false) 
private int userId; 

@Column(name = "name", nullable = false, length = 45) 
private String name; 

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL,mappedBy = "id.user") 
private Set<UserGroup> userGroups = new HashSet<UserGroup>(0); 
//Getters, setters, etc... 
} 

Group.java

@Entity 
@Table(name = "Group") 
public class Group implements java.io.Serializable { 

private static final long serialVersionUID = 4428563096071107683L; 

@Id 
@GeneratedValue(strategy = GenerationType.IDENTITY) 
@Column(name = "groupID", unique = true, nullable = false) 
private int groupId; 

@Column(name = "name", nullable = false, length = 45) 
private String name; 

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL,mappedBy = "id.group") 
private Set<UserGroup> userGroups = new HashSet<UserGroup>(0); 
} 

UserGroup.java

@Entity 
@Table(name = "UserGroup") 
public class UserGroup implements java.io.Serializable { 

private static final long serialVersionUID = 5495027289164828327L; 

@EmbeddedId  
private UserGroupId id; 

@Column(name = "defaultGroup") 
private Boolean defaultGroup; 
} 

UserGroupdId.java

@Embeddable 
public class UserGroupId implements java.io.Serializable { 

private static final long serialVersionUID = -3806643465171954306L; 

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) 
@JoinColumn(name = "groupID", nullable = false, insertable = false, updatable = false) 
private Group group; 

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) 
@JoinColumn(name = "userID", nullable = false, insertable = false, updatable = false) 
private User user; 
} 

TestCode

User u = new User(); 
u.setName("User"); 

Group g = new Group(); 
g.setName("Group"); 


UserGroup ug = new UserGroup(); 
UserGroupId id = new UserGroupId(); 
ug.setId(id); 
ug.getId().setGroup(g); 
ug.getId().setUser(u); 

ug.setDefaultGroup(false); 
u.getUserGroups().add(ug); 


session.saveOrUpdate(u); 

日志条目

[DEBUG] 2017-08-03 10:19:43.497 [main] SQL - insert into M2M.User (name) values (?) 
[DEBUG] 2017-08-03 10:19:43.497 [main] SQL - insert into M2M.User (name) values (?) 
[TRACE] 2017-08-03 10:19:43.510 [main] BasicBinder - binding parameter [1] as [VARCHAR] - [User] 
[TRACE] 2017-08-03 10:19:43.510 [main] BasicBinder - binding parameter [1] as [VARCHAR] - [User] 
[DEBUG] 2017-08-03 10:19:43.541 [main] IdentifierGeneratorHelper - Natively generated identity: 65 
[DEBUG] 2017-08-03 10:19:43.541 [main] ResourceRegistryStandardImpl - HHH000387: ResultSet's statement was not registered 
[DEBUG] 2017-08-03 10:19:43.546 [main] SQL - select usergroup_.groupID, usergroup_.userID, usergroup_.defaultGroup as defaultG1_2_ from M2M.UserGroup usergroup_ where usergroup_.groupID=? and usergroup_.userID=? 
[DEBUG] 2017-08-03 10:19:43.546 [main] SQL - select usergroup_.groupID, usergroup_.userID, usergroup_.defaultGroup as defaultG1_2_ from M2M.UserGroup usergroup_ where usergroup_.groupID=? and usergroup_.userID=? 
[ERROR] 2017-08-03 10:19:43.546 [main] M2MTest - org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance beforeQuery flushing: m2m.Group 
+0

https://en.wikibooks.org/wiki/Java_Persistence/ManyToMany#Bi-directional_Many_to_Many –

正如我explained in this article,这是没有意义的@ManyToOne协会级联。

此外,层叠多对多使得没有感觉,因为两个实体都是父实体,而连接表是这两个父关系的子对象。

所以,你有两个选择:

  1. 如果你想map the join table,你需要单独和级联保存UserGroupUserGroup当您设置关联的两侧。
  2. 您可以跳过映射连接表,级联将按预期工作。但是,在这种情况下,请确保使用Sets而不是Lists。查看this article了解更多详情。