json 无法写入内容:未能延迟初始化角色集合

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42089966/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 18:46:54  来源:igfitidea点击:

Could not write content: failed to lazily initialize a collection of role

jsonspringhibernateHymanson

提问by KostasC

I have One-To-Many relationship, here is my code

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

@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
}

And I am getting the exception:

我得到了例外:

org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: failed to lazily initialize a collection of role: com.example.helios.model.Catalog.items, could not initialize proxy - no Session; nested exception is com.fasterxml.Hymanson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.example.helios.model.Catalog.items, could not initialize proxy - no Session org.springframework.http.converter.json.AbstractHymanson2HttpMessageConverter.writeInternal(AbstractHymanson2HttpMessageConverter.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)

org.springframework.http.converter.HttpMessageNotWritableException:无法写入内容:无法延迟初始化角色集合:com.example.helios.model.Catalog.items,无法初始化代理 - 没有会话;嵌套异常是 com.fasterxml.Hymanson.databind.JsonMappingException:未能延迟初始化角色集合:com.example.helios.model.Catalog.items,无法初始化代理 - 没有会话 org.springframework.http.converter.json .AbstractHymanson2HttpMessageConverter.writeInternal(AbstractHymanson2HttpMessageConverter.java:271) org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:100) org.springframework.web.servletProcess.mvc.noterMessage.

My versions is:

我的版本是:

  • SpringFramework 4.2.4.RELEASE
  • Hibernate 4.3.11.Final
  • Hymanson 2.7.4
  • Hymansontype 2.7.1
  • SpringFramework 4.2.4.RELEASE
  • 休眠 4.3.11.Final
  • Hyman逊 2.7.4
  • Hyman逊型 2.7.1

回答by Angelo Immediata

This is the normal Hibernate behaviour

这是正常的休眠行为

In one to many relations, hibernate loads the father entity (Catalog in your case) but it will load the children entities List (List items and List orders in your case) in a LAZY mode

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

This means you can't access to these objects because they are just proxies and not real objects

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

This is usefull in order to avoid to load the full DB when you execute a query

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

You have 2 solution:

您有 2 个解决方案:

  1. Load children entities in EAGER mode (I strongly suggest to you to not do it because you can load the full DB.... but it is something related to your scenario
  2. You don't serialize in your JSON the children entities by using the com.fasterxml.Hymanson.annotation.JsonIgnore property
  1. 以 EAGER 模式加载子实体(我强烈建议您不要这样做,因为您可以加载完整的数据库....但这与您的场景有关
  2. 您不会使用 com.fasterxml.Hymanson.annotation.JsonIgnore 属性在 JSON 中序列化子实体

Angelo

安杰洛

回答by otonglet

A third option which can be useful if you don't want to use EAGER mode and load up everything is to use Hibernate::initialize and only load what you need.

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

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

More information

更多信息

回答by Cruz Ortiz

I had the same problem but a fixed by:

我有同样的问题,但通过以下方式修复:

@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;

you can have more information here: https://vladmihalcea.com/the-best-way-to-handle-the-lazyinitializationexception/

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

回答by Emerica

It's caused by an infinite loop when parsing datas to JSON.

它是由将数据解析为 JSON 时的无限循环引起的。

You can solve this by using @JsonManagedReferenceand @JsonBackReferenceannotations.

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

Definitions from API :

来自 API 的定义:

Example:

例子:

Owner.java:

所有者.java:

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

Car.java:

汽车.java:

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

Another solution is to use @JsonIgnorewhich will just set null to the field.

另一种解决方案是使用@JsonIgnorewhich 只会将 null 设置为该字段。

回答by Balconsky

Here is my solution for this task with Hibernate. I marked hibernate releation with @JsonIgnore and use custom field for Hymanson, in which I check if the field is loaded. If you need serialize collection to json then you should manualy call collection getter during hibernate transaciton.

这是我使用 Hibernate 完成此任务的解决方案。我用@JsonIgnore 标记了hibernate 关联,并为Hymanson 使用自定义字段,在其中我检查该字段是否已加载。如果您需要将集合序列化为 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;
}

回答by A. kay

I know this is an old post but this might still help someone facing a similar issue. To solve the problem, iterate through the list of items and set the lazy-loadable collection to null. Then set your mapper to include NON-NULL

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

 for (Catalog c : allCatalogs) {
        c.setItems(null);
    }

objectMapper.setSerializationInclusion(Include.NON_NULL)

回答by Golam Morshed Maruf

"You don't serialize in your JSON the children entities by using the com.fasterxml.Hymanson.annotation.JsonIgnoreproperty"

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

Add @JsonIgnorefor hibernate lazy loading properties eg. @ManyToOne. That should work

添加@JsonIgnore休眠延迟加载属性,例如。@ManyToOne. 那应该工作

回答by mykey

Using FetchType.LAZY , if still getting the error "Could not write content: failed to lazily initialize a collection of role" , that may be probably caused by somewhere in the logic (perhaps in a controller) , Catalog is being tried to be deserialized that contains list of catalog items which is a proxy but the transaction has already ended to get that. So create a new model ('CatalogResource' similar to catalog but without the list of items). Then create a catalogResource object out of the Catalog (which is returned from the query)

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

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

回答by Christian Nwafor

I think the best solution to your problem (which also is the simplest) is to set your FetchType to LAZY and simply annotate the oneToMany collection fields using @transient. Setting FetchType to EAGER isn't a good idea most times. Best of luck.

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