首先是所用软件的一些细节:我在 Wildfly 14.0.1Final 和 JSF 2.3 上使用 primefaces 6.2.11。
问题描述:我有两个与many2many 相关的实体(用户和组),我想删除不是所有者的关系(具有mappedBy 的实体)。我不能更改所有者,因为这是遗留代码。我知道我必须删除两端的关系,但我的代码不起作用。将值添加到列表中没有问题,但无法删除它们。几天前我用 Wildfly 10 试过这个,没问题,但新的不行。
一个问题是,primefaces 列表在删除项目时不会通过 ajax 事件通知我。如果是这种情况,我可以处理从我的组列表和组中的用户列表中删除。因为我没有这样的事件,所以我试图在我的服务中处理这个试图拯救用户的事件。
我有两个实体:
@Entity
@Table(name = "USER")
public class User implements Serializable {
private static final long serialVersionUID = -1699265057144017750L;
@Column(name = "ID", nullable = false)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "USER_NAME", length = 45, unique = true)
@Basic
@NotNull
private String userName;
@ManyToMany(fetch = FetchType.LAZY, targetEntity = Group.class, mappedBy = "userList")
@OrderBy("groupName")
private Set<Group> groupList;
// getter setter ...
}
@Entity
@Table(name = "GROUP")
public class User implements Serializable {
private static final long serialVersionUID = -3403518747362744630L;
@Column(name = "ID", nullable = false)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@ManyToMany(fetch = FetchType.LAZY, targetEntity = User.class, cascade = {CascadeType.MERGE, CascadeType.PERSIST})
@JoinTable(name = "USER_GROUP",
joinColumns = {@JoinColumn(name = "GROUP_ID", referencedColumnName = "ID")},
inverseJoinColumns = {@JoinColumn(name = "USER_ID", referencedColumnName = "ID")})
@OrderBy("userName")
private Set<User> userList;
// getter setter ...
}
我创建了一个表单来编辑用户。此表单有很多输入,其中一个用于向用户添加和删除组。这是一个简单的primefaces selectCheckboxMenu。这允许用户选择新组并删除旧组。值直接从用户实体中检索,并且可以选择的值由单独的服务提供。
<p:selectCheckboxMenu id="groupList" multiple="true" filter="true" filterMatchMode="contains"
value="#{editUserBean.authUser.groupList}"
required="true" requiredMessage="At least one group is needed"
converter="cs.argos.gui.jsf.converter.groupConverter" collectionType="java.util.LinkedHashSet">
<f:selectItems value="#{groupService.groups}" var="group" itemValue="#{group}" itemLabel="#{group.authGroupName}"/>
</p:selectCheckboxMenu>
转换器:
@FacesConverter(value = "groupConverter", managed = true)
public class GroupConverter implements Converter {
@Inject
GroupService groupService;
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if(null == value || value.isEmpty()) {
return null;
}
try {
return groupService.getGroupWithCollections(Integer.parseInt(value));
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage("Invalid Group ID"), e);
}
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
Group group = (Group) value;
if (null == group) {
return "";
}
if(null != group.getId()) {
return ""+group.getId();
} else {
throw new ConverterException(new FacesMessage("Invalid Group ID"));
}
}
}
当使用按下按钮时,我正在调用以下服务:
@Transactional(Transactional.TxType.REQUIRED)
public User persistWithDeps(User user2Save) {
User user = user = baseEm.contains(user2Save) ? user2Save : baseEm.merge(user2Save);
// Check if we have a new object (case when: baseEm.merge(user2Save))
if (user != user2Save) {
if (null != user.getGroupList()) {
// remove groups
if (!user2Save.getGroupList().containsAll(user.getGroupList())) {
// remove groups from user
Iterator<Group> iterator = user.getGroupList().iterator();
while (iterator.hasNext()) {
Group group = iterator.next();
if (!user2Save.getGroupList().contains(group)) {
group.getuser2SaveList().remove(user);
iterator.remove();
}
}
}
// Add groups to user
user.getGroupList().forEach(group -> {
if (!group.getUserList().contains(user)) {
group.getUserList().add(user);
}
});
}
}
baseEm.persist(user);
return user;
}