有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Spring boot JPA延迟加载不适用于一对一映射

请注意,我已经研究了类似的问题,并解释了为什么这些问题对我不起作用

我有一个简单的Spring boot JPA Hibernate应用程序,在用户和地址之间有一对一的映射。(请注意,我没有一对多映射的问题)

用户实体

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

    }

我的问题是,每当我调用控制器mapped来获取所有用户时,我都会获取地址以及与之相关的所有注释。但我希望FetchType.LAZY能解决这个问题

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

Post 1

那年春天我也读了。jpa。在视图中打开解除值可能是罪魁祸首:

Post 2

Post 3

因此,我尝试了以下选项:

我通过将spring.jpa.open-in-view=false添加到我的application.properties中禁用了默认的“在视图中打开”属性,该属性开始为我提供

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

我假设这是因为Jackson正在调用我的延迟加载对象的getter,所以我按照另一篇文章中的说明添加了以下内容,以便Jackson不使用延迟加载的集合:

波姆。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());
            }
        }
    }

}

上面的这个解决方案修复了一对多映射的问题,但是仍然有响应中关联的地址

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

我已经尝试了所有我能在网上找到的东西,但到目前为止仍然没有任何效果。我真的很感激你能帮我

如其中一位用户所述,这可能是另一个问题的重复,因此: Suggested Possible duplicate 我想提到的是,我通过禁用spring实现了延迟加载。jpa。在视图中打开属性,但添加

mapper.registerModule(new Hibernate5Module());

返回响应中与用户关联的地址


共 (3) 个答案

  1. # 1 楼答案

    你可以看看Jackson Serialization Views

    我已经了解了您尝试的Hibernate5模块,它有一些有趣的特性。。。但是没有人应该为您解决这个问题

    顺便说一句,我通常通过不返回实体作为响应,而是返回DTO来解决这个问题

  2. # 2 楼答案

    问题是jackson在写入JSON时触发初始化,所以不要写入当前字段(地址)。但是您不应该使用@jsonIgnore,因此在其他地方可以返回Eagerobj

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

    创建视图类:

    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