首先,请详细说明所使用的软件:我正在使用JSF 2.3在Wildfly 14.0.1Final上使用primefaces 6.2.11。
问题描述:我有两个与many2many相关的实体(用户和组),并且我要删除不是所有者(具有mappedBy的实体)这一侧的关系。我不能更改所有者方面,因为这是旧代码。我知道我必须删除两端的关系,但是我的代码无法正常工作。将值添加到列表中没问题,但是无法删除它们。 几天前,我在Wildfly 10上进行了尝试,还可以,但是在新版本上却不行。
一个问题是,素数列表在删除项目时不会通过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 ...
}
我创建了一个表单来编辑用户。该表格有很多输入,一个用于向用户添加和删除组。这是一个简单的素面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;
}
答案 0 :(得分:0)
与JPA有关。您将级联放在错误的实体上:
@ManyToMany(fetch = FetchType.LAZY, targetEntity = Group.class, mappedBy = "userList", , cascade = {CascadeType.MERGE, CascadeType.PERSIST})
然后,您确实会坚持下去。合并:
baseEm.merge(user);
Persist必须仅用于创建新对象。由于您要更新对象,因此请使用合并。
此外,方法persistWithDeps以一种非常奇怪的方式编写。当Primefaces正确更新User对象中的groupList时,就足够了:
public User persistWithDeps(User user2Save) {
return baseEm.merge(user2save);
}
JPA将自动生成必要的SQL,以删除或添加多对多表中的组实体。
还请注意,添加和删除操作基于幕后的equals和哈希码。它们必须正确编程,否则,将无反应。
因此,请尝试将其替换为我的方法。如果仍然不起作用,请在return baseEm.merge(user2save);
上放置一个断点,然后检查user.getGroupList()。它必须具有您期望的正确数量的组。如果是这样,并且合并仍然无法进行,则需要更改equals和hashcode方法。如果在断点上的组数量不正确,那是您所不希望的,这意味着在您的JSF链接bean(editUserBean)和对persistWithDeps的调用之间出现了问题。
顺便说一句,您的selectCheckboxMenu标签和转换器看起来还可以。
祝你好运!