java - Wicket - 持久化和非持久化 JPA 实体的序列化

标签 java jpa serialization wicket

我知道在将 Wicket 与 JPA 框架一起使用时,不建议将已经持久保存到数据库中的实体序列化(因为惰性字段存在问题并节省空间)。在这种情况下,我们应该使用 LoadableDetachableModel。但是以下用例呢?

假设我们要创建一个新实体(例如,一个契约(Contract)),其中包括持久实体(例如,从存储在数据库中的客户列表中选择的客户)。正在创建的实体是某个 Wicket 组件(例如 Wizard)的模型对象。最后(当我们完成向导时)我们将新实体保存到数据库中。所以我的问题是:此类模型对象的序列化问题的最佳通用解决方案是什么?我们不能使用 LDM,因为该实体还不在数据库中,但我们也不希望我们的内部实体(如客户端)也被完全序列化。

我的想法是实现一个自定义 wicket 序列化程序,它检查对象是否是一个实体以及它是否持久化。如果是这样,只存储它的 id,否则使用默认序列化。同样,反序列化时使用存储的 id 并从数据库中获取实体或使用默认机制反序列化。但是,不确定如何以通用方式做到这一点。我的下一个想法是,如果我们能做到,那么我们就不再需要任何 LDM,我们可以将所有实体存储在简单的 org.apache.wicket.model.Model 模型中,我们的序列化逻辑将处理它们,对吧?

这是一些代码:

  @Entity
  Client {
     String clientName;

     @ManyToOne(fetch = FetchType.LAZY)
     ClientGroup group;
  }

  @Entity
  Contract {
     Date date;

     @ManyToOne(fetch = FetchType.LAZY)
     Client client;
  }

  ContractWizard extends Wizard {
     ContractWizard(String markupId, IModel<Contract> model) {
        super(markupId);
        setDefaultModel(model);
     }
  }

  Contract contract = DAO.createEntity(Contract.class);
  ContractWizard wizard = new ContractWizard("wizard", ?); 

如何传递合约?如果我们只说 Model.of(contract) 整个合约将与内部客户端一起序列化(而且它可能很大),此外,如果我们在反序列化后访问 contract.client.group,我们可能会遇到问题:https://en.wikibooks.org/wiki/Java_Persistence/Relationships#Serialization.2C_and_Detaching

所以我想知道人们是如何着手解决这些问题的,我敢肯定这是一个相当普遍的问题。

最佳答案

我想有两种方法可以解决您的问题:

a.) 仅保存用户在模型中实际看到的内容。在您的示例中,可能是“contractStartDate”、“contractEndDate”、clientIds 列表。如果您不想在 View 中显示 DatabaseObject,这是主要方法。

b.) 编写您自己的 LoadableDetachableModel 并确保您只序列化 transient 对象。例如像:(假设任何负id没有保存到数据库中)

public class MyLoadableDetachableModel extends LoadableDetachableModel {

private Object myObject;

private Integer id;

public MyLoadableDetachableModel(Object myObject) {
    this.myObject = myObject;
    this.id = myObject.getId();
}

@Override
protected Object load() {
    if (id < 0) {
        return myObject;
    }

    return myObjectDao.getMyObjectById(id);
}

@Override
protected void onDetach() {
    super.onDetach();
    id = myObject.getId();

    if (id >= 0) {
        myObject = null;
    }
}
}

这样做的缺点是您必须使您的 DatabaseObjects Serializable 这不是很理想并且可能导致各种问题。您还需要使用 ListModel 将对其他实体的引用与 transient 对象分离。

在使用过这两种方法后,我个人更喜欢第一种。根据我的经验,整个将 Dao 对象注入(inject) wicket 会导致灾难。 :) 我只会在不太大的仅供查看的项目中使用它。

关于java - Wicket - 持久化和非持久化 JPA 实体的序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39719201/

相关文章:

Java HashSet 以奇怪的顺序显示列表,总是从 3 开始

java - 如何建立基于非关键字段的关系?

java - 将 Java 对象中的数据写入 XML 文件

java - cucumber 命令行选项不会覆盖@CucumberOptions

java - 从给定区间创建一组大小为 K 的子集 - 使用 Java 中的 Set

java - 反转整数的数字

java - JPA Hibernate 在@ElementCollection 上选择不同的并进行比较

java - JPA:从另一个表加载值列表

使用 FsPickler 对可选值进行 JSON 序列化

java - 如果我们不在 Java 中序列化对象会发生什么?