Hibernate与SparkJava不兼容?

问题描述 投票:3回答:1

我在延迟加载模式下使用Hibernate和SparkJava时出错。

它在没有SparkJava的情况下正常工作,但在使用SparkJava时,它试图强制加载OneToMany关系。

- 模型

@Entity
@Table(name = "KU_SUPPLIER")
public class Supplier {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @NotEmpty(message = "Please provide a name")
    private String name;

    @OneToMany(mappedBy = "supplier")
    private List<Item> items;  // Should be lazy-loaded

    // Constructor / Getters / Setters
}

- DAO

public class SupplierDao implements Dao<Supplier> {

    private final SessionFactory sessionFactory;

    public SupplierDao(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Supplier> findAll() {
        try (Session session = sessionFactory.openSession()) {
            return session.createQuery("FROM com.seafrigousa.model.Supplier").getResultList();
        }
    }
}

- 主要

// Working perfectly and lazy-load Items as desired    
supplierDao.findAll();

// The method will be called when a web browser goes to "localhost/suppliers"
// It throws org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: model.Supplier.items, could not initialize proxy - no Session
get("/suppliers", "application/json", supplierDao::findAll);

我没有从DAO关闭会话进行检查,我看到Hibernate正在执行查询,就像它处于EAGER加载模式一样,因此它执行了两个选择,一个用于供应商,一个用于项目。

这种行为有原因吗?

谢谢!

java hibernate lazy-initialization spark-java
1个回答
2
投票

我想在这里:get("/suppliers", "application/json", supplierDao::findAll);你将供应商对象序列化为json。 Items字段未标记为从序列化中排除,因此获取其值会导致会话中的延迟初始化(或者如果会话未关闭,则会对项目进行冗余和第二次查询)。

如果我的猜测是正确的,请使您的序列化程序忽略项目字段或在查询中获取它们

session.createQuery("FROM com.seafrigousa.model.Supplier s join fetch s.items").getResultList();

使用gson作为序列化程序,您有以下选项:

  1. 要对序列化的字段进行@Expose注释。 @Entity @Table(name = "KU_SUPPLIER") public class Supplier { @Expose @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @Expose @NotEmpty(message = "Please provide a name") private String name; @OneToMany(mappedBy = "supplier") private List<Item> items; // Should be lazy-loaded // Constructor / Getters / Setters } 随着gson的开始 Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
  2. 具有自定义注释的ExclusionStrategy f.e。 public class IgnoreFieldExclusionStrategy implements ExclusionStrategy { @Override public boolean shouldSkipField(FieldAttributes fieldAttributes) { return fieldAttributes.getAnnotation(GsonIgnore.class) != null; } @Override public boolean shouldSkipClass(Class<?> aClass) { return false; } } 使用自定义注释@GsonIgnore @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface GsonIgnore {} 和gson启动 Gson gson = new GsonBuilder().addSerializationExclusionStrategy(new IgnoreFieldExclusionStrategy()).create(); 你的班级看起来像这样 @Entity @Table(name = "KU_SUPPLIER") public class Supplier { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @NotEmpty(message = "Please provide a name") private String name; @GsonIgnore @OneToMany(mappedBy = "supplier") private List<Item> items; // Should be lazy-loaded // Constructor / Getters / Setters }

如果你需要在不同的api中使用Supplier序列化items,你可以为Supplier创建DTO对象并从结果中映射它,如下所示:

package com.seafrigousa.dto

public class SupplierDTO {

    private int id;
    private String name;

    public SupplierDTO(int id, String name) {
        this.id = id;
        this.name = name;
   }

    // Getters / Setters
}

和查询:

session.createQuery("select new com.seafrigousa.dto.SupplierDTO(s.id, s.name) FROM com.seafrigousa.model.Supplier s").getResultList();
© www.soinside.com 2019 - 2024. All rights reserved.