【问题标题】:Could not write content: failed to lazily initialize a collection of role无法写入内容:无法懒惰地初始化角色集合
【发布时间】:2017-02-07 12:30:24
【问题描述】:

我有一对多的关系,这是我的代码

@Entity
@Table(name = "catalog")
public class Catalog {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "catalog_id")
    private int catalog_id;

    @NotEmpty
    @Size(min = 3, max = 255)
    @Column(name = "name", nullable = false)
    private String name;

    @OneToMany(mappedBy="mycatalogorder")
    private List<Order> orders;

    @OneToMany(mappedBy="mycatalog")
    private List<CatalogItem> items;

    // setters and getters
}

 @Entity
 @Table(name = "catalogitem")
 public class CatalogItem {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "catalogitem_id")
    private int catalogitem_id;

    @NotEmpty
    @Size(min = 3, max = 255)
    @Column(name = "name", nullable = false)
    private String name;

    @NotEmpty
    @Column(name = "price", nullable = false)
    private Double price;

    @OneToOne(mappedBy="ordercatalogitem", cascade=CascadeType.ALL)
    private OrderItem morderitem;

    @ManyToOne
    @JoinColumn(name="catalog_id", nullable=false)
    private Catalog mycatalog;

    // setters and getters
}

@Entity
@Table(name = "orders")
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "order_id")
    private int order_id;

    @NotEmpty
    @Size(min = 3, max = 255)
    @Column(name = "name", nullable = false)
    private String name;

    @NotEmpty
    @Size(min = 3, max = 1024)
    @Column(name = "note", nullable = false)
    private String note;

    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(pattern = "ddmmYYYY HH:mm:ss")
    @Column(name = "created", nullable = false)
    private Date created;

    @OneToMany(mappedBy="myorder")
    private Set<OrderItem> orderItems;

    @ManyToOne
    @JoinColumn(name="catalog_id", nullable=false)
    private Catalog mycatalogorder;

    @PrePersist
    protected void onCreate() {
        created = new Date();
    }

    // setters and getters
}

@Entity
@Table(name = "orderitem")
public class OrderItem {

    @Id
    @Column(name="catalogitem_id", unique=true, nullable=false)
    @GeneratedValue(generator="gen")
    @GenericGenerator(name="gen", strategy="foreign", parameters=@Parameter(name="property", value="catalogitem"))
    private int catalogitem_id;

    @Column(name = "quantity")
    private int quantity;

    @OneToOne
    @PrimaryKeyJoinColumn
    private CatalogItem ordercatalogitem;

    @ManyToOne
    @JoinColumn(name="order_id", nullable=false)
    private Order myorder;
     // setters and getters
}

我得到了例外:

org.springframework.http.converter.HttpMessageNotWritableException: 无法写入内容:未能延迟初始化集合 角色:com.example.helios.model.Catalog.items,无法初始化 代理 - 没有会话;嵌套异常是 com.fasterxml.jackson.databind.JsonMappingException: 懒惰失败 初始化角色集合: com.example.helios.model.Catalog.items,无法初始化代理 - 没有会话 org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:271) org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:100) org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:222) org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:183) org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:80) org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:126)

我的版本是:

  • SpringFramework 4.2.4.RELEASE
  • 休眠 4.3.11.Final
  • 杰克逊 2.7.4
  • 杰克逊型 2.7.1

【问题讨论】:

    标签: json spring hibernate jackson


    【解决方案1】:

    这是正常的休眠行为

    在一对多关系中,hibernate 加载父实体(在您的情况下为目录),但它会以 LAZY 模式加载子实体列表(在您的情况下为列表项和列表订单)

    这意味着您无法访问这些对象,因为它们只是代理而不是真实对象

    这对于避免在执行查询时加载完整数据库很有用

    您有 2 个解决方案:

    1. 在 EAGER 模式下加载子实体(我强烈建议您不要这样做,因为您可以加载完整的数据库....但这与您的场景有关
    2. 不要使用 com.fasterxml.jackson.annotation.JsonIgnore 属性在 JSON 中序列化子实体

    安杰洛

    【讨论】:

    • 但第二种解决方案是静态的。在项目中,我们有时需要相关实体,有时不需要。这个 EntityManager 生命周期与 spring 完成的自动序列化是一个可怕的陷阱。
    【解决方案2】:

    如果您不想使用 EAGER 模式并加载所有内容,第三个选项可能很有用,即使用 Hibernate::initialize 并仅加载您需要的内容。

    Session session = sessionFactory.openSession();
    Catalog catalog = (Catalog) session.load(Catalog.class, catalogId);
    Hibernate.initialize(shelf);
    

    More information

    【讨论】:

    • 是的……你说得对……我忘了;但您必须始终处于休眠状态
    • @AngeloImmediata 确实它不是最实用的。当 EAGER 对性能影响太大时使用。
    • 我完全同意你的看法 :)
    【解决方案3】:

    我遇到了同样的问题,但由以下人员解决:

    @OneToMany
    @JoinColumn(name = "assigned_ingredient", referencedColumnName = "ingredient_id")
    @Fetch(FetchMode.JOIN) // Changing the fetch profile you can solve the problem
    @Where(clause = "active_ind = 'Y'")
    @OrderBy(clause = "meal_id ASC")
    private List<Well> ingredients;
    

    您可以在这里获得更多信息:https://vladmihalcea.com/the-best-way-to-handle-the-lazyinitializationexception/

    【讨论】:

      【解决方案4】:

      这是在将数据解析为 JSON 时出现死循环造成的。

      您可以通过使用@JsonManagedReference@JsonBackReference 注释来解决此问题。

      API 定义:

      例子:

      Owner.java:

      @JsonManagedReference
      @OneToMany(mappedBy = "owner", fetch = FetchType.EAGER)
      Set<Car> cars;
      

      Car.java:

      @JsonBackReference
      @ManyToOne(fetch = FetchType.EAGER)
      @JoinColumn(name = "owner_id")
      private Owner owner;
      

      另一种解决方案是使用@JsonIgnore,它只会将字段设置为空。

      【讨论】:

        【解决方案5】:

        这是我使用 Hibernate 完成此任务的解决方案。我用@JsonIgnore 标记了休眠关系,并为杰克逊使用了自定义字段,我在其中检查该字段是否已加载。如果您需要将集合序列化为 json,那么您应该在休眠事务期间手动调用集合 getter。

        @JsonIgnore
        @OneToMany(mappedBy = "myorder")
        private List<OrderItem> orderItems = new ArrayList<>();
        
        @JsonProperty(value = "order_items", access = JsonProperty.Access.READ_ONLY)
        private List<OrderItem> getOrderItemsList() {
        
            if(Hibernate.isInitialized(this.relatedDictionary)){
                return this.relatedDictionary;
            } else{
                return new ArrayList<>();
            }
        }
        
        @JsonProperty(value = "order_items", access = JsonProperty.Access.WRITE_ONLY)
        private void setOrderItemsList(List<OrderItem> orderItems) {
            this.orderItems = orderItems;
        }
        

        【讨论】:

          【解决方案6】:

          我知道这是一篇旧帖子,但这可能仍然可以帮助面临类似问题的人。要解决此问题,请遍历项目列表并将延迟加载集合设置为 null。然后将您的映射器设置为包含 NON-NULL

           for (Catalog c : allCatalogs) {
                  c.setItems(null);
              }
          
          objectMapper.setSerializationInclusion(Include.NON_NULL)
          

          【讨论】:

            【解决方案7】:

            使用 FetchType.LAZY ,如果仍然收到错误“无法写入内容:未能延迟初始化角色集合”,这可能是由逻辑中的某个地方(可能在控制器中)引起的,正在尝试目录要反序列化,其中包含作为代理的目录项列表,但事务已经结束以获取它。 因此,创建一个新模型(类似于目录但没有项目列表的“CatalogResource”)。 然后从 Catalog 中创建一个 catalogResource 对象(从查询中返回)

            public class CatalogResource {
                private int catalog_id;
                private String name;
                private List<Order> orders;
            } 

            【讨论】:

              【解决方案8】:

              我认为您的问题的最佳解决方案(也是最简单的)是将您的 FetchType 设置为 LAZY 并使用 @transient 简单地注释 oneToMany 集合字段。 大多数时候,将 FetchType 设置为 EAGER 并不是一个好主意。 祝你好运。

              【讨论】:

                【解决方案9】:

                “您不会使用 com.fasterxml.jackson.annotation.JsonIgnore 属性在 JSON 中序列化子实体”

                为休眠延迟加载属性添加@JsonIgnore,例如。 @ManyToOne。应该可以的

                【讨论】:

                  猜你喜欢
                  • 2016-06-16
                  • 1970-01-01
                  • 2021-01-30
                  • 2014-05-03
                  • 2016-03-30
                  • 2021-06-15
                  • 2016-11-10
                  • 2020-11-25
                  • 2011-07-21
                  相关资源
                  最近更新 更多