【问题标题】:JPA MERGE failed to update entity field value when this field is a collection(using ElementCollection)当此字段为集合时,JPA MERGE 无法更新实体字段值(使用 ElementCollection)
【发布时间】:2013-06-24 16:05:49
【问题描述】:

这里我们有一个包含学生和教师列表的清单类,两者都可以为空。

class Manifest{
    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "MANIFEST_STUDENT")
    List<String> students = new ArrayList<String>();

    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "MANIFEST_TEACHER")
    List<String> teachers = new ArrayList<String>();;

    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "MANIFEST_OTHERS")
    List<String> others = new ArrayList<String>();;
}

在 UI 上,有两个multiple select,一个用于student,一个用于teacher,供用户选择当前清单。

问题来了:

当用户 deselect all studentsteachers 从列表中(意味着从当前 manifest 中删除所有学生或教师)并单击保存时,不幸的是,从 UI 和数据库中无法保存任何内容,这表明multiselect 选择看起来像以前一样 SAME

从服务层看,代码就是这样。

manifest.merge();

看来我们必须保留 at least one 学生或教师的集合字段才能使更改有效。那么这里发生了什么,解决方案是什么?顺便说一句,我们在 Openjpa 上。

【问题讨论】:

  • 你让我们猜测很多细节。对我们进行假设不太可能对您有所帮助。提供 JPA 注释、表模式的一些(简单)想法等会有所帮助。由于您已将此确定为 JPA 问题,因此我们不再对您的 UI 或其工作方式感兴趣。这样的细节只会混淆核心问题。准确了解您的代码(可能在 UI 中)如何与 JPA 实体交互。设置什么,以及如何设置。简单的代码 sn-ps 会有所帮助。最后,如果生成了异常,则显示异常。它们在这里是相关的。

标签: spring jakarta-ee jpa ejb


【解决方案1】:

解决问题,更像是一种解决方法:

在调用merge()之前,放置几个条件检查器以确保集合字段不为空

public void save(Manifest entity) {

    if(entity.getStudents()==null){
        entity.setStudents(new ArrayList<String>());
    }

    if(entity.getTeachers()==null){
        entity.setTeachers(new ArrayList<String>());
    }

    if(entity.getOthers()==null){
        entity.setOthers(new ArrayList<String>());
    }

    entity.merge();
}

虽然很简单,但 UI 似乎将这些集合字段返回为 null,即使我们将它们启动为空字符串列表。

干杯。

【讨论】:

    【解决方案2】:

    初始化 JPA 托管类中的值(例如 class Manifest)与 JPA 将在 JPA 将提取的行映射到类时创建类的内容或方式无关。具体来说,结果:

    List<String> students = new ArrayList<String>();
    

    可能是:

    • 在创建(通过 JPA)新实例时,将 ArrayList&lt;String&gt;() 分配给 students
    • JPA 用它提取的数据覆盖students - 空的ArrayList 被取消引用/丢失。

    如果您的代码正在清除列表,例如students,请使用obj.getStudents().clear()。如果您致电obj.setStudents(someEmptyList),则更有可能遇到问题。

    这里的问题是 JPA 管理器如何处理空数据集:作为 null 或作为 空列表。 JPA 规范(旧的,不确定刚刚发布的更新)在这一点上没有立场。一个relevant article here

    从您的 cmets 来看,很明显 OpenJPA 可能不尊重 Collection/Listnull 值,而当值设置为空列表时,它很乐意管理必要的更改。在这个阶段,比我更了解 OpenJPA 的人可能无法提供帮助 - 同时您有一个解决方法。

    【讨论】:

    • 这很有帮助,谢谢。所以有两个问题:(1)如果 obj.getStudents() 是 null ,我还能使用 clear() 方法吗? (2)调用obj.setStudents(someEmptyList)会出现什么问题?
    • 1. clearly 不是。 2. 遇到问题时,我个人的偏执狂。 真正的问题尚未解决(恕我直言,由于问题陈述中缺乏细节)是为什么这些值是null?您暗示存在“问题”-那是什么?什么例外?合并之前和之后的数据表中有什么 - 对象在修改之前、修改之后和合并之前有什么?
    • 这是一个 Spring MVC 应用程序,当用户取消选择所有选项时,Spring 将 UI 中的 dom 列表值(即使先生您不感兴趣 :),但仍然是事实)为 null,就像我提到的并点击保存按钮。也不例外。即用户想要从学生列表中删除所有人,目前它只包含亚当和鲍勃。用户取消选择它们并点击保存后,该页面应显示没有在学生列表中选择任何人。但是A和B还在。我使用调试模式可以看到,在我删除 A 和 B 并点击保存按钮后,清单对象返回 students==null。
    • 我再次猜测,没有键入 OpenJPA,但是如果您更改设置器会发生什么: setStudents(List students) { if (students == null) this.students.清除();否则 this.students = 学生; }
    • 我建议可能存在 bug(或者,对于 OpenJPA 纯粹主义者,可能是一个特性 :-) 和可能的解决方法。
    猜你喜欢
    • 2021-10-15
    • 2019-09-21
    • 1970-01-01
    • 2018-08-24
    • 1970-01-01
    • 2013-02-28
    • 1970-01-01
    • 1970-01-01
    • 2011-03-29
    相关资源
    最近更新 更多