【问题标题】:Spring One-To-Many relationship throws Exception : org.springframework.http.converter.HttpMessageNotWritableExceptionSpring 一对多关系抛出异常: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

标签: java spring spring-data-jpa spring-rest


【解决方案1】:

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

以下是我做过的事情

  1. 在服务方法中声明了@Transactional。
  2. 在持久性 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(",")));
    }

}
  1. 正在根据持久性 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"}) 吗?好的,这会在其反序列化过程中为延迟获取的数据进行初始化,因为这些数据在您第一次调用该对象时并未获取。另外,请检查我的编辑
    • 是的,我已经添加了整个注释
    猜你喜欢
    • 1970-01-01
    • 2016-09-10
    • 2018-05-27
    • 2018-11-26
    • 1970-01-01
    • 2016-09-26
    • 2019-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多