gpt4 book ai didi

java - 无法写入 JSON : failed to lazily initialize a collection of role

转载 作者:搜寻专家 更新时间:2023-11-01 01:40:17 25 4
gpt4 key购买 nike

我尝试使用 java - hibernate - spring 实现服务器 REST,它返回一个 json。

我映射了一个多对多的关系。

我解释得更好,我有一个供应商,上面有一个成分列表,每个成分都有一个供应商列表。

我创建了表格:

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

然后我有成分模型:

.....
.....
@ManyToMany(mappedBy = "ingredients")
@OrderBy("created DESC")
@BatchSize(size = 1000)
private List<Supplier> suppliers = new ArrayList<>();
....
....

然后我有供应商模型:

....
@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<>();
....

端点:

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

}

服务

....
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;
}
....

供应商对象

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


}
}

IdAbstractObject

public abstract class IdAbstractObject{

public Long id;

}

我的问题是,当我调用端点时:

http://localhost:8080/supplier/1

我遇到了一个错误:

"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.jackson.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\"])"

我遵循了这个:

Avoid Jackson serialization on non fetched lazy objects

现在我没有错误,但是在返回的 json 中,成分字段为空:

{
"id": 1,
"email": "mail@gmail.com",
"phoneNumber": null,
"address": null,
"responsible": null,
"companyName": "Company name",
"vat": "vat number",
"ingredients": null
}

但在调试中我可以看到成分....

enter image description here

最佳答案

这是 Hibernate 和 Jackson Marshaller 的正常行为基本上你想要以下内容:一个包含所有供应商对象详细信息的 JSON...包括成分。

请注意,在这种情况下您必须非常小心,因为当您尝试创建 JSON 本身时可能会产生循环引用,因此您还应该使用 JsonIgnore 注释

您必须做的第一件事是加载供应商及其所有详细信息(包括成分)。

你怎么做到的?通过使用几种策略...让我们使用 Hibernate.initialize .这必须在 DAO(或存储库)实现(基本上是您使用 hibernate session 的地方)中的 hibernate session 关闭之前使用

所以在这种情况下(我假设使用 Hibernate)在我的存储库类中我应该写这样的东西:

public Supplier findByKey(Long id)
{
Supplier result = (Supplier) getSession().find(Supplier.class, id);
Hibernate.initialize(result.getIngredients());
return result;
}

现在你有了 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;
}

通过这种方式,Jackson 能够编写 JSON but让我们看看 Ingredient对象..它具有以下属性:

@ManyToMany(mappedBy = "ingredients")
@OrderBy("created DESC")
@BatchSize(size = 1000)
private List<Supplier> suppliers = new ArrayList<>();

当 Jackson 尝试创建 JSON 时会发生什么?它将访问 List<Ingredient> 中的每个元素。它也会尝试为此创建一个 JSON……也为供应商列表创建一个 JSON,这是一个循环引用……所以你必须避免它,你可以通过使用 JsonIgnore 注释来避免它。例如你可以写你的 Ingredient这样的实体类:

@JsonIgnoreProperties(value= {"suppliers"})
public class Ingredient implements Serializable
{
......
}

这样你:

  • 用所有相关成分加载供应商对象
  • 尝试创建 JSON 本身时避免循环引用

无论如何,我建议您创建特定的 DTO(或 VO)对象以用于编码和解码 JSON

希望对你有用

安杰洛

关于java - 无法写入 JSON : failed to lazily initialize a collection of role,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48117059/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com