Spring Boot JPA-延迟加载不适用于一对一映射 [英] Spring boot JPA - Lazy loading is not working for One to One mapping

查看:92
本文介绍了Spring Boot JPA-延迟加载不适用于一对一映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请注意,我已经看过类似的问题,并且已经解释了为什么它们没有为我工作

我有一个简单的Spring boot JPA-Hibernate应用程序,其中User和Address之间是一对一的映射. (请注意,我没有一对多映射的问题)

I have a simple Spring boot JPA-Hibernate application with one to one mapping between User and Address. (Please note that I do not have this issue with one to many mapping)

用户实体

@Entity
    @Table(name = "users")
    public class User implements Serializable {

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        private Integer id;

        @Column
        private String name;

        @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
        private Address address;

        @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
        private Set<Note> notes;

    }

地址实体

   @Entity
    @Table(name = "addresses")
    public class Address implements Serializable {

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        private Integer id;

        @Column
        private String street;

        @Column
        private String city;

        @JsonIgnore
        @OneToOne
        @JoinColumn(name = "user_id")
        private User user;

    }

注释实体

@Entity
    @Table(name = "notes")
    public class Note implements Serializable {

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        private Integer id;

        @Column
        private String date;

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

    }

我的问题是,每当我调用映射为要获取所有用户的控制器时,我都会得到该地址以及所有相关的注释.但是我希望FetchType.LAZY能够解决这个问题.

My problem is that whenever I call the controller mapped to get all users I was getting the address and all the associated notes with it as well. But I would expect FetchType.LAZY to take care of that.

我在StackOverflow上阅读了很多问题,提到杰克逊可能是罪魁祸首:

I read a lot of questions on StackOverflow mentioning that Jackson might be the culprit here:

帖子1

我还阅读到spring.jpa.open-in-view defualt值可能是罪魁祸首:

I also read that spring.jpa.open-in-view defualt value might be the culprit:

帖子2

帖子3

所以我尝试了以下选项:

So i tried the following options:

我通过向application.properties添加spring.jpa.open-in-view=false来禁用默认打开的视图属性,该属性开始为我提供

I disabled default open in view property by adding spring.jpa.open-in-view=false to my application.properties which started giving me

Could not write JSON: failed to lazily initialize a collection of role error

我认为这是因为杰克逊正在对我的惰性加载对象调用吸气剂,所以我遵循了另一篇文章的说明,并为杰克逊添加了以下内容,以使惰性加载的集合不再存在:

I am assuming its because Jackson is calling the getters on my lazily loaded objects so I followed the instructions from another post and added the following for Jackson to leave the lazily loaded collections alone:

pom.xml

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-hibernate5</artifactId>
    <version>2.9.9</version>
</dependency>

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        for (HttpMessageConverter converter : converters) {
            if (converter instanceof org.springframework.http.converter.json.MappingJackson2HttpMessageConverter) {
                ObjectMapper mapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();
                mapper.registerModule(new Hibernate5Module());
            }
        }
    }

}

以上解决方案通过一对多"映射解决了该问题,但响应中仍关联了地址".

This solution above fixed the issue with the One to Many mapping but still has the Address associated in the response.

我不确定在这里可以做什么.默认登录页面上的用户实体不需要任何地址详细信息,因此我不想将其加载到登录页面上.当单击记录时,它将导航到另一页,这是我希望在响应中返回所有延迟加载的对象的地方.

I am not sure what can I do here. The User Entity on the default landing page does not need any address details so I do not want to load it on the landing page. When the record is clicked then it navigates to another page and that's where I would like all the lazy loaded objects to be returned in the response.

我已经尝试了所有可以在网上找到的内容,但到目前为止,仍然没有任何效果.我真的很感谢您的帮助.

I have tried everything I could find online but still nothing has worked so far. I would really appreciate some help with this.

正如一个用户提到的那样,它可能是另一个关于SO的问题的副本: 建议可能的重复项 我想提到的是,我通过禁用spring.jpa.open-in-view属性但添加了

As mentioned by one of the users that it might a duplicate of another question on SO: Suggested Possible duplicate I would like to mention that I got the Lazy loading working by disabling spring.jpa.open-in-view property but adding

mapper.registerModule(new Hibernate5Module());

带回与用户在响应中关联的地址.

brings back the address associated to the User in the response.

推荐答案

问题是杰克逊在编写JSON时会触发初始化,因此不要编写当前字段(地址).但是您不应该使用@jsonIgnore,因此在其他地方您可以返回Eager obj.

The problem is jackson triggering initialization when he writes the JSON, so just don't write the current field (address). But you should not use @jsonIgnore so at other places you could return an Eager obj.

您可以使用@jsonView批注,该批注可以在不同的请求下为同一obj提供不同的JSON.您可以看一下以下示例:

You can use the @jsonView annotation that can provide different JSON for the same obj at different requests. You can look this example :

创建视图类:

public class ViewFetchType {
    static class lazy{ }
    static class Eager extends lazy{ }
}

注释您的实体

@Entity
public class User {

    @Id
    @JsonView(ViewFetchType.Lazy.class)
    private String id;

    @JsonView(ViewFetchType.Eager.class)
    @OneToOne( fetch = FetchType.LAZY)
    private Address address ;
}

在控制器中指定FetchType类:

public class UserController {

    private final UserRepository userRepository;

    @Autowired
    UserController(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @RequestMapping("get-user-details")
    @JsonView(ViewFetchType.Eager.class)
    public @ResponseBody Optional<User> get(@PathVariable String email) {
        return userRepository.findByEmail(email);
    {

    @RequestMapping("get-all-users")
    @JsonView(ViewFetchType.Lazy.class)
    public @ResponseBody List<User> getUsers() {
        return userRepository.findAll();
    }
}

这是我从...中获得灵感的答案. https://stackoverflow.com/a/49207551/10162200

Here is the answer that i took the idea from... https://stackoverflow.com/a/49207551/10162200

这篇关于Spring Boot JPA-延迟加载不适用于一对一映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆