上下文
有一个应用程序使用springmvc和springdatajpa。jpa提供程序是hibernate,视图层由jsp页面表示。
有一个用于创建新用户的页面。通过此页创建新用户时,该用户被分配到一个用户组(从列表中选择)。这个 User
是新的但选定的 Group
此时已存在。这个
User @Entity
有一套 Group
其中的对象。两者之间的双向关联 User
s和 Group
s是 @ManyToMany
还有一张table( group_members
)链接这些实体。
当视图图层经过 User
对象到控制器 setGroups(Set<Group> groups)
方法在 User
. 那么这个呢 User
对象通过 userDetailsService.add(user)
哪个是 @Transactional
.
问题
这个 Group
在呈现页面时,这些对象被加载到视图中,然后它们与持久化单元分离。在坚持 User
,关联的 Group
是分离的 Group
边与边不同步 User
. 这个 User
实体定义了同步事务双方的实用方法( addGroup(Group group)
以及 removeGroup(Group group)
)但是我找不到一种方法来使用它们,因为这种方法只能在服务层中创建的事务之外调用它们。
问题
在这种情况下,保持所有实体始终处于有效状态的最佳方法是什么?用户和组都应该传递到服务层吗?
代码
为了简洁起见,省略了一些部分。
创建用户.jsp
<body>
<sf:form id="details" method="post" action="${pageContext.request.contextPath}/docreate" modelAttribute="user">
<h2>Sing up</h2>
<table class="formtable">
<tr>
<td class="label">Userame: </td> <td><sf:input path="username" name="username" type="text" /> <div class="error"> <sf:errors path="username"></sf:errors> </div></td>
</tr>
<tr>
<td class="label">Password: </td> <td><sf:input id="password" path="password" name="password" type="password" /> <div class="error"><sf:errors path="password"></sf:errors> </div></td>
</tr>
<tr>
<td class="label">Confirm password: </td> <td><input id="confirmpass" name="confirmpass" type="password" /> <div id="matchpass"></div></td>
</tr>
<tr>
<td class="label" align="right">Group</td><td><sf:select id="groups" path="groups" items="${groups}" itemValue="id"
itemLabel="groupName"/></td>
</tr>
<tr>
<td> </td> <td class="button"><input value="Create user" type="submit" /> </td>
</tr>
</table>
</sf:form>
</body>
用户控制器.java
@RequestMapping(value="/docreate", method=RequestMethod.POST)
public String doCreate(Model model, @Validated(FormValidationGroup.class) User user, BindingResult result) {
// User validation ...
user.setEnabled(true);
// Duplicate user check ...
userDetailsService.add(user);
return "usercreated";
}
userdetailsserviceimpl.java
@Transactional
public void add(User user) {
if (!contains(user.getUsername())) {
userRepository.save(user);
}
}
用户.java
@Entity
@Table(name="users",schema="sec")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String username;
private String password;
private boolean enabled;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name="group_members", schema="sec", joinColumns= { @JoinColumn(name="user_id") }, inverseJoinColumns = { @JoinColumn(name="group_id") } )
private Set<Group> groups = new HashSet<>();
// ...
public void addGroup(Group group) {
this.groups.add(group);
group.getUsers().add(this);
}
public void removeGroup(Group group) {
this.groups.remove(group);
group.getUsers().remove(this);
}
public void setGroups(Set<Group> groups) {
for (Group group : groups) {
this.groups.add(group);
}
}
}
组.java
@Entity
@Table(name="groups",schema="sec")
public class Group {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String groupName;
// ...
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "groups")
private Set<User> users = new HashSet<>();
// Method to synchronize bidirectional association
public void addUser(User user) {
this.users.add(user);
user.getGroups().add(this);
}
public void removeUser(User user) {
this.users.remove(user);
user.getGroups().remove(this);
}
// ...
public Set<User> getUsers() {
return users != null ? users : new HashSet<>();
}
public void setUsers(Set<User> users) {
this.users = users;
}
// ...
}
1条答案
按热度按时间kgsdhlau1#
由于事务是在服务层中启动的,所以实现此同步的唯一可能选择是
服务层或
道层
服务层定义了
add(user)
方法和步骤set(user)
方法,两者都调用save(user)
方法,因此在包含该方法的dao层中同步关联是合乎逻辑的。此外,引用EntityManager
在道层。