我尝试用java -hib- spring实现一个服务器REST,它返回一个json。
我已经Map了多对多关系。
我解释得更好,我有一个供应商,有一个成分列表,每个成分都有一个供应商列表。
我创建了表:
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();
}
}
和标识抽象对象
public abstract class IdAbstractObject{
public Long id;
}
我的问题是,当我调用端点时:
http://localhost:8080/supplier/1
出现错误:
“无法写入JSON:无法延迟初始化角色集合:无法初始化代理-无会话;嵌套的异常是com.fasterxml.Jackson.databind.jsonMappingException:无法延迟初始化角色集合:myPackage.ingredient.Ingredient.suppliers,无法初始化代理-无会话(通过引用链:我的软件包.供应商.供应商对象[\“成分"]-〉组织.休眠.集合.内部.持久性包[0]-〉我的软件包.成分.成分[\“供应商"])”
我接着说:
避免对未提取的惰性对象进行Jackson序列化
现在我还没有这个错误但是在json返回的时候,配料字段是null:
{
"id": 1,
"email": "mail@gmail.com",
"phoneNumber": null,
"address": null,
"responsible": null,
"companyName": "Company name",
"vat": "vat number",
"ingredients": null
}
但是在调试中我可以看到一些成分....
8条答案
按热度按时间vh0rcniy1#
这是Hibernate和JacksonMarshaller的正常行为。基本上,您需要具有以下内容:包含所有供应商对象详细信息的JSON ......包括配料。
请注意,在这种情况下,您必须非常小心,因为当您尝试创建JSON本身时,可能会有循环引用,因此您还应使用
JsonIgnore
注解您必须做的第一件事是加载供应商及其所有详细信息(包括配料)。
如何做到这一点呢?通过使用几种策略...让我们使用
Hibernate.initialize
。这个必须在DAO(或仓库)实现中的休眠会话关闭之前使用(基本上是在使用休眠会话的地方)。因此,在本例中(我假设使用Hibernate),在我的存储库类中,我应该编写如下内容:
现在,您有了
Supplier
对象及其所有详细信息(也有Ingredients
)。现在,在您的服务中,您可以执行您所执行的操作:通过这种方式,Jackson能够编写JSON
but
。让我们给予看看Ingredient
对象。它具有以下属性:当Jackson尝试创建JSON时会发生什么?它将访问
List<Ingredient>
中的每个元素,并尝试为这个元素创建一个JSON ......也为供应商列表创建一个JSON,这是一个循环引用......所以你必须避免它,你可以通过使用JsonIgnore注解来避免它。例如,你可以这样写你的Ingredient
实体类:这样你:
在任何情况下,我都建议您创建特定的DTO(或VO)对象,以用于编组和解组JSON
我希望这是有用的
安杰洛
a2mppw5e2#
您有一些解决此问题的解决方案:
1.您可以使用
@ManyToMany(fetch = FetchType.EAGER)
但是从性能的Angular 来看,EAGER取数是非常糟糕的。而且,一旦你有了EAGER关联,你就不可能让它变得懒惰。
1.您可以使用
@ManyToMany @Fetch(FetchMode.JOIN)
更多信息:https://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/FetchMode.html
编辑:当yout
application.properties
文件中包含以下行时,可能会发生此错误:rqenqsqc3#
在我的项目中,我遇到了与您的项目相同的问题。问题是在“一对多”读取数据时,会话已经关闭。要获取所有数据,您需要显式初始化或使用事务。我使用了显式初始化。您需要在DAO中添加一行:
之后,Hibernate将从数据库加载所有数据,为了避免序列化到JSON时产生异常,我在一对多模型字段中添加了
@JsonIgnore
注解。下面是我的代码示例:
1.Model
2.数据访问对象
uklbhaso4#
只需在模型类中的
@oneToMany
之后添加@JsonIgnore
。zynd9foi5#
这是由于休眠会话在惰性初始化开始之前关闭。
下面的答案很好地解释了解决方案。避免对非获取的懒惰对象进行Jackson序列化
d5vmydt96#
您应该使用jackson-datatype-hib。
https://github.com/FasterXML/jackson-datatype-hibernate
并将其添加到您的www.example.com上Application.java
jv4diomz7#
在我的application.properties文件中,spring jpa的open-in-view属性是假的。我必须通过注解来消除这个错误。
希望这能帮助到一些人。
f2uvfpb98#
我不得不将
spring.jpa.open-in-view = true
添加到application.properties