简体   繁体   English

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

[英]How to update more than one object at a time using a JPA OneToMany relationship?

I have Principal and PrincipalRoles entity classes.我有PrincipalPrincipalRoles实体类。 They have a bi-directional “parent-child” relationship defined like this:它们具有如下定义的双向“父子”关系:

Principal has:校长有:

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

PrincipalRoles has: PrincipalRoles具有:

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

I also have a master-detail web page in the Web module of a Java EE application.我在 Java EE 应用程序的 Web 模块中还有一个主从 web 页面。 The page uses the entity classes and their corresponding facades contained in the EJB module of the application.该页面使用应用程序的 EJB 模块中包含的实体类及其对应的外观。

The page obtains the Principal object and later updates it using methods of a Stateless EJB, PrincipalFacadeBean , which basically execute the find and merge methods of the Entity Manager.该页面获取Principal object 并稍后使用无状态 EJB 的方法PrincipalFacadeBean对其进行更新,该方法基本上执行实体管理器的查找合并方法。 The Persistence Context is Container-Managed.持久性上下文是容器管理的。

The page can add and remove several PrincipalRoles and then merge the Principal successfully.该页面可以添加和删除多个PrincipalRoles ,然后成功合并Principal It can also add and remove several PrincipalRoles , update JUST ONE of the previously added and then merge the Principal ;它还可以添加和删除几个PrincipalRoles ,更新之前添加的一个,然后合并Principal but it always fails when attempting to update more than one in a single merge operation.但是当尝试在单个合并操作中更新多个时它总是失败。 In those cases, no exception is raised but nothing is updated in the database.在这些情况下,不会引发异常,但不会在数据库中更新任何内容。 Not even other fields of Principal , like name, e-mail, etc.甚至没有Principal的其他字段,例如姓名、电子邮件等。

The application runs on GlassFish 5.1.0, Java 1.8.0_281, EclipseLink 2.7.4, PostgreSQL 13.该应用程序在 GlassFish 5.1.0、Java 1.8.0_281、EclipseLink 2.7.4、PostgreSQL 13 上运行。

I've been dealing with this problem for a few days now and I'm running out of ideas.我已经处理这个问题几天了,我的想法已经不多了。 Any assistance you can provide would be greatly appreciated.您能提供的任何帮助将不胜感激。

Addendum to answer @crizzis questions :回答@crizzis问题的附录

I'm not sure what the service method would be.我不确定服务方法是什么。 The page bean calls the façade directly using this method:页面 bean 直接使用此方法调用外观:

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

In master-detail pages the list contains only the master.在主从页面中,列表仅包含主页面。 This is the façade’s merge method:这是外观的合并方法:

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

These are the equals and hashCode methods of PrincipalRoles .这些是PrincipalRolesequalshashCode方法。 Actually, these methods have the same template in all entity classes.实际上,这些方法在所有实体类中都有相同的模板。

@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);
}

This is ObjUtils.equals :这是ObjUtils.equals

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

The principal field of the updated PrincipalRoles is the Principal object being merged (at least their System.identityHashCode matches).更新后的PrincipalRoles的主要字段是正在合并Principal object(至少它们的System.identityHashCode匹配)。 I also checked the value of an unmodified PrincipalRoles .我还检查了未修改的PrincipalRoles的值。 That was null .那是null

All I had to do was change the @ManyToOne of the field principal in PrincipalRoles from @ManyToOne(fetch = FetchType.LAZY) to @ManyToOne(fetch = FetchType.EAGER) .我所要做的就是将PrincipalRoles中字段principal@ManyToOne@ManyToOne(fetch = FetchType.LAZY)更改为@ManyToOne(fetch = FetchType.EAGER) I still don't understand why, but it works.我仍然不明白为什么,但它有效。 Thanks again to @crizzis and @Chris.再次感谢@crizzis 和@Chris。 Their questions led me to the answer.他们的问题让我找到了答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM