Hibernate:避免隐式初始化集合

时间:2016-03-14 12:01:47

标签: java hibernate jpa collections jackson

我们将实体类用于两个目的:

  1. 作为数据库模型,即Hibernate @Entity
  2. 作为以JSON
  3. 发送到前端的数据模型

    想象一下@Entity有许多庞大的集合,例如:

    @Entity
    @Table(name = "customer")
    public class Customer {
    
        @Id
        private Integer id;
    
        @Column(name = "name")
        private String name;
    
        @OneToMany(mappedBy = "customer", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
        private List<Order> orders;
    
        @OneToMany(mappedBy = "customer", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
        private List<Counterparty> counterparties;
    
        /* ... a lot of other properties, including collections ... */
    
    }
    

    现在,我们以两种主要方式与Customer合作:

    1. 获取个人客户进行查看/编辑,完成所有馆藏。
    2. 获取客户列表,仅显示其显示所需的“核心”属性;我们不需要加载任何子集合,因为我们没有使用它们,它们会产生很多额外的查询。
    3. 我首选的解决方案是显式初始化集合 1 ,并保留null或为空 2

      问题在于,当Jackson将一个对象序列化为JSON时,它会覆盖所有属性,包括集合属性,因此它们被强制初始化。添加@JsonIgnore不是一个选项(我们需要这些集合用于 1 ),添加@Transient以使Hibernate远离它们也不是一个选项(我们必须能够在编辑后存储馆藏。)

      另一种选择当然是创建一个不带集合的Customer的不同模型,并将其用于场景 2 ,但这意味着维护同一实体的两个变种而且我'我想避免这种情况。

      如何禁用Hibernate隐式加载这些集合,以便只显式初始化(​​例如Hibernate.initialize(customer.orders)),同时保留在需要时保留它们的可能性?

3 个答案:

答案 0 :(得分:1)

在Hibernate中无法做到这一点。

备选方案:

  1. 使用DTO。这样做的好处是可以将要序列化的对象定制为消耗生成的JSON的客户端的确切需求。此外,域模型(Hibernate实体)与序列化逻辑分离,允许两者独立发展。
  2. 使用custom serializers

答案 1 :(得分:1)

最终我在&#34; DTO-fashion&#34;中解决了它。但是开销最小,为每个属性添加一个替代的getter,如下所示:

@Entity
@Table(name = "customer")
public class Customer {

    ...

    @OneToMany(mappedBy = "customer", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JsonIgnore
    private List<Order> orders;

    /* "Normal" getter to be used in the back-end */ 
    @JsonIgnore // <-- Important as it hides it from Jackson
    public List<Order> getOrders() {
        return orders;
    }

    /* Non-initializing getter for serialization for the front-end */ 
    public List<Order> getOrdersNonInit() {
        return Hibernate.isInitialized(orders) ? orders : null;
    }

    ...

}

答案 2 :(得分:0)

以下只是一种可能的解决方案,取决于您的环境。

FasterXML项目中有一个名为“jackson-datatype-hibernate”的项目。您可以在https://github.com/FasterXML/jackson-datatype-hibernate找到它,它允许定义自定义序列化程序,包括禁用惰性字段。 (我认为这个序列化程序的默认值。)

代码可能如下所示:

ObjectMapper mapper = new ObjectMapper();
Hibernate4Module hibernateModule = new Hibernate4Module();
mapper.registerModule(hibernateModule);