如何使用JPA OneToMany关系一次更新多个对象



我有PrincipalPrincipalRoles实体类。他们有一种双向的"父子"关系,定义如下:

委托人拥有:

@OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, orphanRemoval = true, mappedBy = "principal")
Collection<PrincipalRoles> rolesByPrincipalCollection;

主要角色具有:

@JoinColumn(name = "principal", referencedColumnName = "id", nullable = false, insertable = true, updatable = true, unique = false)
@ManyToOne(fetch = FetchType.LAZY)
Principal principal;

在JavaEE应用程序的web模块中,我还有一个主细节网页。该页面使用应用程序的EJB模块中包含的实体类及其相应的外观。

页面获取Principal对象,然后使用无状态EJB的方法PrimaryFacadeBean对其进行更新,这些方法基本上执行实体管理器的findmerge方法。持久性上下文是容器管理的。

页面可以添加和删除多个主体角色,然后成功合并主体。它还可以添加和删除几个PrincipalRoles,更新之前添加的JUST ONE然后合并Principal;但当尝试在单个merge操作中更新多个时,它总是失败。在这些情况下,不会引发异常,但数据库中不会更新任何内容。甚至连委托人的其他字段都没有,如姓名、电子邮件等。

该应用程序运行在GlassFish 5.1.0、Java 1.8.0_281、EclipseLink 2.7.4、PostgreSQL 13上。

我已经处理这个问题好几天了,我已经没有什么想法了。如能提供任何帮助,我们将不胜感激。

回答@crizzis问题的附录

我不确定服务方法是什么。页面bean直接使用以下方法调用façade:

@Override
public List<Principal> merge(List<Principal> list) {
return principalFacade.merge(list);
}

在母版详细信息页中,列表仅包含母版。这是立面的合并方法:

@Override
public List<Principal> merge(List<Principal> list) {
List<Principal> m = new ArrayList<>();
for (Principal o : list) {
m.add(_manager.merge(o));
}
return m;
}

这些是PrincipalRolesequalshashCode方法。实际上,这些方法在所有实体类中都有相同的模板。

@Override
public boolean equals(Object obj) {
if (obj instanceof PrincipalRoles) {
PrincipalRoles that = (PrincipalRoles) obj;
return that == this || ObjUtils.equals(id, that.id);
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}

这是ObjUtils.equals:

public static boolean equals(Object a, Object b) {
return (a == b) || (a == null && b == null) || (a != null && b != null && a.equals(b));
}

更新的PrincipalRoles的主体字段是被合并的主体对象(至少它们的System.identityHashCode匹配(。我还检查了未修改的PrincipalRoles的值。那是null

我所要做的就是将PrincipalRoles中字段principal@ManyToOne@ManyToOne(fetch = FetchType.LAZY)更改为@ManyToOne(fetch = FetchType.EAGER)。我仍然不明白为什么,但它有效!再次感谢@crizzis和@Chris。他们的问题使我找到了答案。

最新更新