Spring 一对多关系抛出异常:org.springframework.http.converter.HttpMessageNotWritableException

Posted

技术标签:

【中文标题】Spring 一对多关系抛出异常:org.springframework.http.converter.HttpMessageNotWritableException【英文标题】:Spring One-To-Many relationship throws Exception : org.springframework.http.converter.HttpMessageNotWritableException 【发布时间】:2020-04-28 20:40:50 【问题描述】:

我尝试使用 spring 在两个实体之间创建简单的关系。有一个 User 实体包含许多 profile 实体。

用户实体

@Entity
public class User 

    @OneToMany(mappedBy = "user")
    private List<Profile> profiles;

    public List<Profile> getProfiles() 
        return profiles;
    

    public void setProfiles(List<Profile> profiles) 
        this.profiles = profiles;
    

个人资料实体

@Entity
public class Profile 

    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    public User getUser() 
        return user;
    

    public void setUser(User user) 
        this.user = user;
    

当我尝试在 @RestController 中查找带有 this.profileRepository.findById(id).get() 的个人资料时,我收到此错误:

org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: User.profiles, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: User.profiles, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->User["profiles"])]
The server encountered an unexpected condition that prevented it from fulfilling the request.

谁能向我解释为什么这不起作用?我跟着this教程。

【问题讨论】:

交易已关闭。如果知道需要相关对象,则应该急切地而不是懒惰地获取关系。 本教程中没有“其余控制器”(除了存储库...具有“内置”控制器),您可能只是缺少控制器类/方法上的 @Transactional 注释(like here) ...advanced issue here 【参考方案1】:

我遇到了同样的问题。 但我收到“已解决 [org.springframework.http.converter.HttpMessageNotWritableException:无法写入 JSON:无法延迟初始化角色集合:”的错误消息: 因为我没有在 viewDTO 中声明 toString 方法

以下是我做过的事情

    在服务方法中声明了@Transactional。 在持久性 DTO 中声明该字段如下

 @Convert(converter = StringListConverter.class)
    @JsonIgnore
    @ElementCollection
    protected List<String> someField;
 

在哪里

public class StringListConverter implements AttributeConverter<List<String>, String> 

    @Override
    public String convertToDatabaseColumn(List<String> list) 
        return String.join(",", list);
    

    @Override
    public List<String> convertToEntityAttribute(String joined) 
        return new ArrayList<>(Arrays.asList(joined.split(",")));
    

    正在根据持久性 DTO 创建 viewDTO 并在响应实体中设置 viewDTO。

【讨论】:

【参考方案2】:

正如Mandar所说,你可以通过eager fetch解决它。但是,如果您不想获取所有我的意思是eager fetch,那么您必须将它们初始化为像这样的相关类的延迟获取,您的 Profile 类:

@JsonIgnoreProperties("hibernateLazyInitializer", "handler")
@Entity
public class Profile implements Serializable
//
//
.. your other stuffs

编辑:也像这样改变你的用户实体:

@Entity
public class User implements Serializable

    @OneToMany(mappedBy = "user")
    private List<Profile> profiles = new LinkedHashSet<Profile>();
//...other stufs..
.
.

希望,这会有所帮助!

【讨论】:

顺便说一句:我通常建议将业务实体与持久性实体以及 DTO 分开。所以实际上,这一类应该是三个类:一个用于(外部)表示的 DTO、一个业务实体和一个持久性实体。 感谢您回答我的问题。正如您所描述的,我已将 @JsonIgnoreProperties 添加到配置文件实体中。但这仍然是同样的问题。你能再解释一下吗? @Turing85 你能解释一下业务实体的含义吗? 你添加了这整件事@JsonIgnoreProperties("hibernateLazyInitializer", "handler") 吗?好的,这会在其反序列化过程中为延迟获取的数据进行初始化,因为这些数据在您第一次调用该对象时并未获取。另外,请检查我的编辑 是的,我已经添加了整个注释

以上是关于Spring 一对多关系抛出异常:org.springframework.http.converter.HttpMessageNotWritableException的主要内容,如果未能解决你的问题,请参考以下文章

Nhibernate一对多关系复合键问题

sbs spring aop

使用 Hibernate 删除一对多关系中的对象时 PostgreSQL 异常

Spring boot 无法评估表达式方法抛出 'org.hibernate.LazyInitializationException' 异常。使用 getter,ManyToMany 关系

Spring JDBC中的多个一对多关系

如何与 Spring 和 thymeleaf 创建一对多的关系?