java 无法写入 JSON:未能延迟初始化角色集合
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/48117059/
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
Could not write JSON: failed to lazily initialize a collection of role
提问by Gjord83
I try to implement a server REST with java - hibernate - spring, which returns a json.
我尝试使用 java - hibernate - spring 实现服务器 REST,它返回一个 json。
I have map a many to many relation.
我已经映射了多对多关系。
I explain better, I have a supplier that have a list of ingredients, and each ingredient has a list of supplier.
我解释得更好,我有一个供应商有一份配料清单,每个配料都有一份供应商清单。
I created the table:
我创建了表:
CREATE TABLE supplier_ingredient (
supplier_id BIGINT,
ingredient_id BIGINT
)
ALTER TABLE supplier_ingredient ADD CONSTRAINT supplier_ingredient_pkey
PRIMARY KEY(supplier_id, ingredient_id);
ALTER TABLE supplier_ingredient ADD CONSTRAINT
fk_supplier_ingredient_ingredient_id FOREIGN KEY (ingredient_id)
REFERENCES ingredient(id);
ALTER TABLE supplier_ingredient ADD CONSTRAINT
fk_supplier_ingredient_supplier_id FOREIGN KEY (supplier_id) REFERENCES
supplier(id);
Then I have Ingredientmodel:
然后我有成分模型:
.....
.....
@ManyToMany(mappedBy = "ingredients")
@OrderBy("created DESC")
@BatchSize(size = 1000)
private List<Supplier> suppliers = new ArrayList<>();
....
....
Then I have Suppliermodel:
然后我有供应商模型:
....
@ManyToMany
@JoinTable( name = "supplier_ingredient ",
joinColumns = @JoinColumn(name = "supplier_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "ingredient_id", referencedColumnName = "id"),
foreignKey = @ForeignKey(name = "fk_supplier_ingredient_supplier_id"))
@OrderBy("created DESC")
@Cascade(CascadeType.SAVE_UPDATE)
@BatchSize(size = 1000)
private List<Ingredient> ingredients = new ArrayList<>();
....
Endpoint:
终点:
@RequestMapping(value = "/{supplierId:[0-9]+}", method = RequestMethod.GET)
@ResponseStatus(value = HttpStatus.OK)
@ResponseBody
public SupplierObject get(@PathVariable Long supplierId) {
Supplier supplier = supplierService.get(supplierId);
SupplierObject supplierObject = new SupplierObject (supplier);
return SupplierObject;
}
Service
服务
....
public Supplier get(Long supplierId) {
Supplier supplier = supplierDao.getById(supplierId); (it does entityManager.find(entityClass, id))
if (supplier == null) throw new ResourceNotFound("supplier", supplierId);
return supplier;
}
....
SupplierObject
供应商对象
@JsonIgnoreProperties(ignoreUnknown = true)
public class SupplierObject extends IdAbstractObject {
public String email;
public String phoneNumber;
public String address;
public String responsible;
public String companyName;
public String vat;
public List<Ingredient> ingredients = new ArrayList<>();
public SupplierObject () {
}
public SupplierObject (Supplier supplier) {
id = supplier.getId();
email = supplier.getEmail();
responsible = supplier.getResponsible();
companyName = supplier.getCompanyName();
phoneNumber = supplier.getPhone_number();
ingredients = supplier.getIngredients();
vat = supplier.getVat();
address = supplier.getAddress();
}
}
And IdAbstractObject
和IdAbstractObject
public abstract class IdAbstractObject{
public Long id;
}
My problem is, when I call the endpoint:
我的问题是,当我调用端点时:
http://localhost:8080/supplier/1
I got an error:
我有一个错误:
"Could not write JSON: failed to lazily initialize a collection of role: myPackage.ingredient.Ingredient.suppliers, could not initialize proxy - no Session; nested exception is com.fasterxml.Hymanson.databind.JsonMappingException: failed to lazily initialize a collection of role: myPackage.ingredient.Ingredient.suppliers, could not initialize proxy - no Session (through reference chain: myPackage.supplier.SupplierObject[\"ingredients\"]->org.hibernate.collection.internal.PersistentBag[0]->myPackage.ingredient.Ingredient[\"suppliers\"])"
“无法编写 JSON:无法延迟初始化角色集合:myPackage.ingredient.Ingredient.suppliers,无法初始化代理 - 无会话;嵌套异常为 com.fasterxml.Hymanson.databind.JsonMappingException:无法延迟初始化集合角色:myPackage.ingredient.Ingredient.suppliers,无法初始化代理 - 没有会话(通过参考链:myPackage.supplier.SupplierObject[\"ingredients\"]->org.hibernate.collection.internal.PersistentBag[0]- >myPackage.ingredient.Ingredient[\"供应商\"])"
I followed this:
我跟着这个:
Avoid Hymanson serialization on non fetched lazy objects
Now I haven't the error but in json returned, the ingredients field is null:
现在我没有错误,但在返回的 json 中,成分字段为空:
{
"id": 1,
"email": "[email protected]",
"phoneNumber": null,
"address": null,
"responsible": null,
"companyName": "Company name",
"vat": "vat number",
"ingredients": null
}
but in debug I can see ingredients....
但在调试中我可以看到成分....
回答by Angelo Immediata
This is the normal behaviour of Hibernate and Hymanson Marshaller Basically you want to have the following: a JSON with all Supplier object details... included the Ingredients.
这是 Hibernate 和 Hymanson Marshaller 的正常行为 基本上,您希望拥有以下内容:包含所有供应商对象详细信息的 JSON……包括成分。
Please note that in this case you must be very carefull because you can have a cyclic reference when you try to create the JSON itself so you should use also JsonIgnore
annotation
请注意,在这种情况下,您必须非常小心,因为当您尝试创建 JSON 本身时可能会有循环引用,因此您也应该使用JsonIgnore
注释
The first thing you must do is to load the Supplier and all its details (ingredients included).
您必须做的第一件事是加载供应商及其所有详细信息(包括成分)。
How can you do it? By using several strategies... let's use the Hibernate.initialize
. This must be used before the closing of hibernate sessionthat is in the DAO (or repository) implementation (basically where you use the hibernate session).
你怎么能这样做?通过使用多种策略......让我们使用Hibernate.initialize
. 这必须在关闭DAO(或存储库)实现中的休眠会话之前使用(基本上是您使用休眠会话的地方)。
So in this case (I assume to use Hibernate) in my repository class I should write something like this:
因此,在这种情况下(我假设使用 Hibernate)在我的存储库类中,我应该编写如下内容:
public Supplier findByKey(Long id)
{
Supplier result = (Supplier) getSession().find(Supplier.class, id);
Hibernate.initialize(result.getIngredients());
return result;
}
Now you have the Supplier
object with all its own details (Ingredients
too)
Now in your service you can do what you did that is:
现在您拥有了Supplier
具有所有详细信息的对象(Ingredients
也)现在在您的服务中,您可以执行以下操作:
@RequestMapping(value = "/{supplierId:[0-9]+}", method = RequestMethod.GET)
@ResponseStatus(value = HttpStatus.OK)
@ResponseBody
public SupplierObject get(@PathVariable Long supplierId)
{
Supplier supplier = supplierService.get(supplierId);
SupplierObject supplierObject = new SupplierObject (supplier);
return SupplierObject;
}
In this way Hymanson is able in writing the JSON but
let's give a look to the Ingredient
object.. it has the following property:
通过这种方式,Hymanson 能够编写 JSON,but
让我们看看Ingredient
对象......它具有以下属性:
@ManyToMany(mappedBy = "ingredients")
@OrderBy("created DESC")
@BatchSize(size = 1000)
private List<Supplier> suppliers = new ArrayList<>();
What will happen when Hymanson tries to create the JSON? It will access to the each element inside the List<Ingredient>
and it will try to create a JSON for this one too.... also for the suppliers list and this is a cyclic reference... so you must avoid it and you can avoid it by using the JsonIgnore annotation. For example you may write your Ingredient
entity class in this way:
当 Hymanson 尝试创建 JSON 时会发生什么?它将访问里面的每个元素List<Ingredient>
,它也会尝试为这个元素创建一个 JSON....也用于供应商列表,这是一个循环引用......所以你必须避免它,你可以通过以下方式避免它使用 JsonIgnore 注释。例如,您可以这样编写Ingredient
实体类:
@JsonIgnoreProperties(value= {"suppliers"})
public class Ingredient implements Serializable
{
......
}
In this way you:
通过这种方式,您:
- load the supplier object with all the related ingredient
- avoid a cyclic reference when you try to create the JSON itself
- 使用所有相关成分加载供应商对象
- 尝试创建 JSON 本身时避免循环引用
In any case I would suggest to you to create specific DTO (or VO) object to use for marshalling and unmarshalling JSONs
在任何情况下,我都会建议您创建特定的 DTO(或 VO)对象以用于编组和解组 JSON
I hope this is usefull
我希望这是有用的
Angelo
安杰洛
回答by conacry
In my project I came across the same problem as yours. The problem is that by the time of reading the data "one to many" the session has already been closed. To get all the data, you need to explicitly initialize or use the transaction. I used an explicit initialization. You need to add a line in the DAO:
在我的项目中,我遇到了和你一样的问题。问题是,在“一对多”读取数据时,会话已经关闭。要获取所有数据,您需要显式初始化或使用事务。我使用了显式初始化。您需要在 DAO 中添加一行:
Hibernate.initialize(supplier.getIngredients());
After that, Hibernate will load all the data from the database. To avoid generating an exception when serializing to JSON, I add the @JsonIgnore
annotation in the one-to-many model field.
之后,Hibernate 将从数据库中加载所有数据。为避免在序列化为 JSON 时产生异常,我@JsonIgnore
在一对多模型字段中添加了注释。
Here is an example of my code:
这是我的代码示例:
1.Model
1.型号
@OneToMany(mappedBy = "commandByEv", fetch = FetchType.LAZY)
@JsonIgnore
private Set<Evaluation> evaluations;
2. DAO
2.DAO
public Command getCommand(long id) {
Session session = sessionFactory.getCurrentSession();
Evaluation evaluation = session.get(Evaluation.class, id);
Hibernate.initialize(evaluation.getCommand());
return evaluation.getCommand();
}
回答by veben
You have some solutions to resolve this issue:
您有一些解决方案可以解决此问题:
- You can use
@ManyToMany(fetch = FetchType.LAZY)
- 您可以使用
@ManyToMany(fetch = FetchType.LAZY)
But EAGER fetching is very bad from a performance perspective. Moreover, once you have an EAGER association, there is no way you can make it LAZY.
但是从性能的角度来看,EAGER 获取非常糟糕。此外,一旦你有了一个 EAGER 协会,你就无法让它变得懒惰。
- You can use
@ManyToMany @Fetch(FetchMode.JOIN)
- 您可以使用
@ManyToMany @Fetch(FetchMode.JOIN)
More information: https://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/FetchMode.html
更多信息:https: //docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/FetchMode.html
Edit: It can occur when you have the following line in yout application.properties
file:
编辑:当您的application.properties
文件中有以下行时,可能会发生这种情况:
spring.jpa.open-in-view = false
回答by Majid
Just add @JsonIgnore
after @oneToMany
in your model class.
只需在您的模型类中添加@JsonIgnore
之后即可@oneToMany
。
回答by Nikhil Yekhe
This is due to the hibernate session closed before the lazy initialization kicked in.
这是由于在延迟初始化开始之前休眠会话已关闭。
The solution is explained well at this answer below. Avoid Hymanson serialization on non fetched lazy objects
解决方案在下面的这个答案中得到了很好的解释。 避免对未获取的惰性对象进行 Hymanson 序列化