簡體   English   中英

Spring boot JPA - 延遲加載不適用於一對一映射

[英]Spring boot JPA - Lazy loading is not working for One to One mapping

請注意,我看過類似的問題,並解釋了為什么它們對我不起作用

我有一個簡單的 Spring 啟動 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;

    }

我的問題是,每當我調用映射控制器以獲取所有用戶時,我都會獲取地址以及所有相關的注釋。 但我希望FetchType.LAZY能夠解決這個問題。

我在 StackOverflow 上閱讀了很多問題,提到傑克遜可能是這里的罪魁禍首:

發布 1

我還讀到 spring.jpa.open-in-view 默認值可能是罪魁禍首:

帖子 2

帖子 3

所以我嘗試了以下選項:

我通過將spring.jpa.open-in-view=false到開始給我的application.properties禁用了默認打開視圖屬性

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

我假設它是因為傑克遜在我懶惰加載的對象上調用吸氣劑,所以我按照另一篇文章中的說明添加了以下內容,讓傑克遜獨自離開懶惰加載的集合:

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

}

上面的這個解決方案解決了一對多映射的問題,但在響應中仍然有關聯的地址。

我不確定我能在這里做什么。 默認登陸頁面上的用戶實體不需要任何地址詳細信息,所以我不想在登陸頁面上加載它。 當記錄被點擊時,它會導航到另一個頁面,這就是我希望在響應中返回所有延遲加載的對象的地方。

我已經嘗試了所有可以在網上找到的方法,但到目前為止仍然沒有任何效果。 我真的很感激這方面的一些幫助。

正如其中一位用戶所提到的,它可能與 SO 上的另一個問題重復: 建議可能重復我想提一下,我通過禁用 spring.jpa.open-in-view 屬性來使延遲加載工作,但添加

mapper.registerModule(new Hibernate5Module());

在響應中帶回與用戶關聯的地址。

您可以查看Jackson Serialization Views

我已經查看了您嘗試過的 Hibernate5 模塊,它有一些有趣的功能......但沒有人應該為您解決這個問題。

順便說一下,我通常通過不返回實體作為響應而是返回 DTO 來解決這個問題。

它的工作方式與 JPA 規范一樣:-

請參閱以下 URL https://javaee.github.io/javaee-spec/javadocs/javax/persistence/FetchType.html

LAZY fetching 策略只是一個提示(因為 javadoc 說可以延遲獲取數據)......不是強制性操作。

急切是強制性的(因為 javadoc 說必須急切地獲取數據)。

問題是jackson在寫JSON時觸發了初始化,所以不要寫當前字段(地址)。 但是你不應該使用@jsonIgnore所以在其他地方你可以返回一個Eager obj。

您可以使用@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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM