【问题标题】:Mapping hibernate entity with Jackson annotation使用 Jackson 注释映射休眠实体
【发布时间】:2016-02-14 21:04:57
【问题描述】:

我正在使用 Spring、hibernate 和 MySql,但我在查询结果的序列化方面遇到了一些问题。 首先在我的实体中,我在 Set 结构(@OneToMany 端)上添加了@JsonManagedReference,在单个对象引用(@ManyToOne 端)上添加了@JsonBackReference,它可以工作,但我无法检索所有需要的信息(例如 @ManyToOne 参考) . 所以我在集合结构上交换@JsonBackReference,在单个对象上交换@JsonManagedReference,但我检索了

No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.model.tablesField.TableUI["data"]->java.util.ArrayList[0]->com.domain.Car["carType"]->com.domain.CarType_$$_jvst744_f["handler"])

我也尝试在 Set 结构上使用 @JsonIgnore,但它不适用于相同的问题。 这是我的spring配置

private Properties getHibernateProperties() {
        Properties properties = new Properties();
        properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
//      properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
        properties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
        properties.put("hibernate.enable_lazy_load_no_trans",true);
        return properties;

这是我的几个实体之一的一部分:

   /**
 * Car generated by hbm2java
 */
@Entity
@Table(name = "car", catalog = "ATS")
public class Car implements java.io.Serializable {

        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        private Integer idCar;
        @JsonManagedReference
        private CarType carType;
        @JsonManagedReference
        private Fleet fleet;
        private String id;
        private int initialKm;
        private String carChassis;
        private String note;
        @JsonBackReference
        private Set<Acquisition> acquisitions = new HashSet<Acquisition>(0);

        public Car() {
        }

        public Car(CarType carType, Fleet fleet, int initialKm, String carChassis) {
            this.carType = carType;
            this.fleet = fleet;
            this.initialKm = initialKm;
            this.carChassis = carChassis;
        }

        public Car(CarType carType, Fleet fleet, String id, int initialKm, String carChassis, String note,
                Set<Acquisition> acquisitions) {
            this.carType = carType;
            this.fleet = fleet;
            this.id = id;
            this.initialKm = initialKm;
            this.carChassis = carChassis;
            this.note = note;
            this.acquisitions = acquisitions;
        }

        @Id
        @GeneratedValue(strategy = IDENTITY)

        @Column(name = "id_car", unique = true, nullable = false)
        public Integer getIdCar() {
            return this.idCar;
        }

        public void setIdCar(Integer idCar) {
            this.idCar = idCar;
        }

        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "id_carType", nullable = false)
        public CarType getCarType() {
            return this.carType;
        }

        public void setCarType(CarType carType) {
            this.carType = carType;
        }

        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "id_fleet", nullable = false)
        public Fleet getFleet() {
            return this.fleet;
        }

        public void setFleet(Fleet fleet) {
            this.fleet = fleet;
        }

        @Column(name = "id", length = 5)
        public String getId() {
            return this.id;
        }

        public void setId(String id) {
            this.id = id;
        }

        @Column(name = "initialKm", nullable = false)
        public int getInitialKm() {
            return this.initialKm;
        }

        public void setInitialKm(int initialKm) {
            this.initialKm = initialKm;
        }

        @Column(name = "carChassis", nullable = false, length = 20)
        public String getCarChassis() {
            return this.carChassis;
        }

        public void setCarChassis(String carChassis) {
            this.carChassis = carChassis;
        }

        @Column(name = "note", length = 100)
        public String getNote() {
            return this.note;
        }

        public void setNote(String note) {
            this.note = note;
        }

        @OneToMany(fetch = FetchType.LAZY, mappedBy = "car")
        public Set<Acquisition> getAcquisitions() {
            return this.acquisitions;
        }

        public void setAcquisitions(Set<Acquisition> acquisitions) {
            this.acquisitions = acquisitions;
        }

    }

一种使用查询的方法:

@Override
    @RequestMapping(value = { "/cars/{idFleet}"}, method = RequestMethod.GET)
    public @ResponseBody TableUI getCars(@PathVariable int idFleet) {   
        TableUI ajaxCall=new TableUI();
        try {   
            ajaxCall.setData(fleetAndCarService.findCarsByIdFleet(idFleet));
            return ajaxCall;
        } catch (QueryException e) {
            ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(e);
            LOG.error("Threw exception in FleetAndCarControllerImpl::addCar :" + errorResponse.getStacktrace());
            return ajaxCall;
        }
    }

查询的两个类:

public interface DefRdiRepository extends JpaRepository<DefRdi, Integer>{


    //@Query("SELECT CASE WHEN COUNT(c) > 0 THEN true ELSE false END FROM DefRdi c WHERE c.parName = ?1 AND c.description= ?2")
    //Boolean existsByParNameAndDescription(String parName, String description);
    //Query method of spring, I put findBy and then the key of research 
    DefRdi findByParNameAndDescription(String parName, String description);
}

public interface CarRepository extends JpaRepository<Car, Integer>, CarRepositoryCustom {

    //Query method of spring, I put findBy and then the key of research 
    List<Car> findByFleetIdFleet(int idFleet);

}

我的错误在哪里?我不想要 Set 对象,而只想要单个引用。问题仅在我序列化时。谢谢

更新: 我在所有集合集合上使用@JSonIgnore,而 Eager 代替惰性广告一切正常,但是有没有办法只在我想要的时候检索所有信息,例如有两个不同的查询? 所以它不起作用

@Override
@Transactional
public List<Car> findByFleetIdFleet(int idFleet) {
    List<Car> carList= carRepository.findByFleetIdFleet(idFleet);
    for (Car car:carList){
        Hibernate.initialize(car.getCarType());
        Hibernate.initialize(car.getFleet());
    }
    return carList; 
    //      return carRepository.findByFleetIdFleet(idFleet);
}

【问题讨论】:

    标签: java mysql spring hibernate jackson


    【解决方案1】:

    在从数据库加载它们时,所有集合都需要急切地获取,以便被 Spring 序列化。确保您急切地获取它们(例如 FetchMode.JOIN)。您还可以将带有@JsonIgnore 的所需字段中的@JsonManagedReference 交换为黑名单字段,Spring 会自动序列化每个字段而无需注释。

    更新

    将数据存储库更改为类似的东西应该可以,我不确定它是否可以编译,但我想你会明白的:

    @EntityGraph(value = "some.entity.graph", type = EntityGraph.EntityGraphType.FETCH)
    @Query(
            value = "SELECT c FROM Car c INNER JOIN FETCH c.acquisitions WHERE c.id = :idFleet"
    )
    public interface CarRepository extends JpaRepository<Car, Integer>, CarRepositoryCustom {
    
          //Query method of spring, I put findBy and then the key of research 
          List<Car> findByFleetIdFleet(int idFleet);
    
    }
    

    有关更多信息,请查看this 帖子并阅读official documentation

    解决方法:

    似乎有一个workaround,但是像上面显示的那样获取那些急切的集合应该会对性能产生积极的影响,因为之后不需要加载代理。在控制器级别也不需要打开事务。

    【讨论】:

    • 我尝试在黑名单字段(所有集合)上仅使用@JsonIgnore,但它不起作用。我用 fetchType 更新了上面的代码,我用的是 LAZY
    • 这就是问题所在。在 Spring 想要序列化您的集合的那一刻,由于延迟加载,没有集合只有代理。您有两种选择:在加载时急切地获取您需要的集合(推荐),或者将映射类型更改为急切。
    • 如何急切地获取收藏?在没有@JsonIgnore 的情况下对我的所有外部对象使用 Hibernate.initialize?否则,如果我使用 model.addAttribute("fleets",fleetAndCarService.getFleets()) 没有问题发生
    • 取决于你如何加载它们,Criteria,HQL,Spring Data,JDBC...?只需添加您的代码。
    • 我更新了我的第一篇文章和上面的问题,如果我必须对所有对象使用 hibernnate.initialize ,我可以使用 eager ,是一样的吗?
    猜你喜欢
    • 1970-01-01
    • 2010-10-06
    • 1970-01-01
    • 2019-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-03
    相关资源
    最近更新 更多