【问题标题】:Nested one-to-many problem in spring data JPASpring Data JPA中的嵌套一对多问题
【发布时间】:2019-03-27 07:46:19
【问题描述】:

表格:

survey(id, title);
survey_question(id, survey_id, title);
survey_question_option(id, survey_question_id, content)

实体:

@Entity
public class Survey implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    @OneToMany(mappedBy = "survey", fetch = FetchType.EAGER, orphanRemoval = true, cascade = CascadeType.ALL)
    private List<SurveyQuestion> questions;

}

@Entity
public class SurveyQuestion implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @JoinColumn(nullable = false)
    @ManyToOne
    @JsonIgnore
    private Survey survey;

    private String title;

    @OneToMany(mappedBy = "surveyQuestion", fetch = FetchType.EAGER, orphanRemoval = true, cascade = CascadeType.ALL)
    private List<SurveyQuestionOption> options;

}

@Entity
public class SurveyQuestionOption implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @JoinColumn(nullable = false)
    @ManyToOne
    @JsonIgnore
    private SurveyQuestion surveyQuestion;

    private String content;

}

现在添加调查

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Survey create(@RequestBody Survey survey) {
    return repository.save(survey);
}

请求正文中的 JSON

{
    "title": "I'm a survey!",
    "questions": [{
        "title": "I'm a question!",
        "options": [{
            "content": "I'm an option."
        },
        {
            "content": "I'm an option."
        },
        {
            "content": "I'm an option."
        },
        {
            "content": "I'm an option."
        }]
    },
    {
        "title": "I'm a question!",
        "options": [{
            "content": "I'm an option."
        },
        {
            "content": "I'm an option."
        },
        {
            "content": "I'm an option."
        },
        {
            "content": "I'm an option."
        }]
    }]
}

成功,那么表格如下:

调查:

id    title
---------------------------------------
46    I'm a survey!

调查问题:

id    survey_id    title
---------------------------------------
34    46           I'm a question!
35    46           I'm a question!

survey_question_option:

id    survey_question_id    content
---------------------------------------
17    34                    I'm an option!
18    34                    I'm an option!
19    34                    I'm an option!
20    34                    I'm an option!
21    35                    I'm an option!
22    35                    I'm an option!
23    35                    I'm an option!
24    35                    I'm an option!

现在,当我按页面获得所有调查时

@GetMapping
public Page<Survey> findAll(Pageable page) {
    return repository.findAll(page);
}

回答正确,2题,每题4个选项

{
    "content": [{
        "id": 46,
        "title": "I'm a survey!",
        "questions": [{
            "id": 34,
            "title": "I'm a question!",
            "options": [{
                "id": 17,
                "content": "I'm an option."
            },
            {
                "id": 18,
                "content": "I'm an option."
            },
            {
                "id": 19,
                "content": "I'm an option."
            },
            {
                "id": 20,
                "content": "I'm an option."
            }]
        },
        {
            "id": 35,
            "title": "I'm a question!",
            "options": [{
                "id": 21,
                "content": "I'm an option."
            },
            {
                "id": 22,
                "content": "I'm an option."
            },
            {
                "id": 23,
                "content": "I'm an option."
            },
            {
                "id": 24,
                "content": "I'm an option."
            }]
        }]
    }],
    "page": 1,
    "size": 20,
    "totalPages": 1,
    "totalCount": 1
}

但是,当我收到这样的 id 调查时:

@GetMapping("/{id:\\d+}") // 46
public Survey get(@PathVariable Long id) {
    return repository.findById(id).orElse(null);
}

回答让我很困惑,一共8个问题

{
    "id": 46,
    "title": "1111111111111",
    "questions": [{
        "id": 34,
        "title": "I'm a question!",
        "options": [{
            "id": 17,
            "content": "I'm an option."
        },
        {
            "id": 18,
            "content": "I'm an option."
        },
        {
            "id": 19,
            "content": "I'm an option."
        },
        {
            "id": 20,
            "content": "I'm an option."
        }]
    },
    {
        "id": 34,
        "title": "I'm a question!",
        "options": [{
            "id": 17,
            "content": "I'm an option."
        },
        {
            "id": 18,
            "content": "I'm an option."
        },
        {
            "id": 19,
            "content": "I'm an option."
        },
        {
            "id": 20,
            "content": "I'm an option."
        }]
    },
    {
        "id": 34,
        "title": "I'm a question!",
        "options": [{
            "id": 17,
            "content": "I'm an option."
        },
        {
            "id": 18,
            "content": "I'm an option."
        },
        {
            "id": 19,
            "content": "I'm an option."
        },
        {
            "id": 20,
            "content": "I'm an option."
        }]
    },
    {
        "id": 34,
        "title": "I'm a question!",
        "options": [{
            "id": 17,
            "content": "I'm an option."
        },
        {
            "id": 18,
            "content": "I'm an option."
        },
        {
            "id": 19,
            "content": "I'm an option."
        },
        {
            "id": 20,
            "content": "I'm an option."
        }]
    },
    {
        "id": 35,
        "title": "I'm a question!",
        "options": [{
            "id": 21,
            "content": "I'm an option."
        },
        {
            "id": 22,
            "content": "I'm an option."
        },
        {
            "id": 23,
            "content": "I'm an option."
        },
        {
            "id": 24,
            "content": "I'm an option."
        }]
    },
    {
        "id": 35,
        "title": "I'm a question!",
        "options": [{
            "id": 21,
            "content": "I'm an option."
        },
        {
            "id": 22,
            "content": "I'm an option."
        },
        {
            "id": 23,
            "content": "I'm an option."
        },
        {
            "id": 24,
            "content": "I'm an option."
        }]
    },
    {
        "id": 35,
        "title": "I'm a question!",
        "options": [{
            "id": 21,
            "content": "I'm an option."
        },
        {
            "id": 22,
            "content": "I'm an option."
        },
        {
            "id": 23,
            "content": "I'm an option."
        },
        {
            "id": 24,
            "content": "I'm an option."
        }]
    },
    {
        "id": 35,
        "title": "I'm a question!",
        "options": [{
            "id": 21,
            "content": "I'm an option."
        },
        {
            "id": 22,
            "content": "I'm an option."
        },
        {
            "id": 23,
            "content": "I'm an option."
        },
        {
            "id": 24,
            "content": "I'm an option."
        }]
    }]
}

请告诉我如何解决这个问题?

【问题讨论】:

    标签: java hibernate jpa spring-data-jpa


    【解决方案1】:

    您同时使用fetch = FetchType.EAGER

    private List<SurveyQuestion> questions;
    

    private List<SurveyQuestionOption> options;
    

    所以默认情况下你总是在这里获取整棵树。

    现在这里的关键是您将这些依赖项声明为List。这意味着有序但允许重复。在这里,您会根据选项的数量得到一个重复的问题。

    尽量使用SetSortedSet 以避免重复。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-30
      • 1970-01-01
      • 1970-01-01
      • 2020-09-12
      • 2019-01-24
      • 2020-06-23
      • 1970-01-01
      • 2019-07-30
      相关资源
      最近更新 更多