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

如何使用JPA OneToMany关系一次更新多个对象?,jpa,merge,eclipselink,one-to-many,container-managed,Jpa,Merge,Eclipselink,One To Many,Container Managed,我有主体和主体角色实体类。它们具有双向“父子”关系,定义如下: 主要负责人有: @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, orphanRemoval = true, mappedBy = "principal") Collection<PrincipalRoles> rolesByPrinc

我有主体主体角色实体类。它们具有双向“父子”关系,定义如下:

主要负责人有:

@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模块中,我还有一个主细节web页面。页面使用应用程序EJB模块中包含的实体类及其对应的外观

页面获取主体对象,然后使用无状态EJB的方法主体对其进行更新,该方法基本上执行实体管理器的查找合并方法。持久性上下文由容器管理

页面可以添加和删除多个主要角色,然后合并主要角色。它还可以添加和删除多个主要角色,只更新先前添加的一个,然后合并主要角色;但在一次合并操作中尝试更新多个时,它总是失败。在这些情况下,不会引发异常,但数据库中不会更新任何内容。甚至连主体的其他字段也没有,比如姓名、电子邮件等

该应用程序运行在GlassFish 5.1.0、Java 1.8.0281、EclipseLink 2.7.4和PostgreSQL 13上

我已经处理这个问题好几天了,现在我已经没有主意了。如果您能提供任何帮助,我们将不胜感激

回答@crizzis问题的附录

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

@Override
public List<Principal> merge(List<Principal> list) {
    return principalFacade.merge(list);
}
这是
对象。等于

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

更新的PrincipalRoles的主体字段是合并的主体对象(至少其
系统.identityHashCode
匹配)。我还检查了未修改的PrincipalRoles的值。这就是
null

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

请发布相关的服务方法。如何为
主要角色
实现
equals/hashCode
?保存时,更新的
PrincipalRoles
principal
字段的值是多少?致@crizzis:首先,感谢您的回答。我对这些评论的格式有很多吹捧,所以我在原始帖子中添加了我的答案。当这些主要角色与主要角色关联时,它们来自哪里?您是否已更新此Principal Principal Roles关系的双方,如果这些Principal Roles是预先存在的,那么在更改之前它们可能引用了哪一个主体实体?您可以尝试打开SQL日志记录以查看生成的查询以及何时验证它们与您期望的匹配()。根据您的操作和访问惰性关系的时间,可能会触发类似cascade.refresh的事件。@Chris,谢谢您的回答。由于急于获取,预先存在的PrincipalRoles与Principal一起出现。该页面更新该集合,然后调用主facade将其合并。当我激活EclipseLink日志记录时,只有在失败时选择。但在每一种情况下(添加和删除的任意组合),日志都会显示预期的SQL语句。令人费解的是,页面可以添加和删除任意数量的角色,并更新一个(并且只更新一个)。现在我想知道,为什么它能更新一个?
@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);
}
public static boolean equals(Object a, Object b) {
    return (a == b) || (a == null && b == null) || (a != null && b != null && a.equals(b));
}