Вложенная проблема «один ко многим» в весенних данных JPA - PullRequest
0 голосов
/ 27 марта 2019

Таблица:

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!

survey_question:

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
}

НО, когда я получаю один опрос по идентификатору, как это:

@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."
        }]
    }]
}

Скажите, пожалуйста, как я могу решить эту проблему?

1 Ответ

1 голос
/ 27 марта 2019

Вы используете fetch = FetchType.EAGER как для

private List<SurveyQuestion> questions;

, так и для

private List<SurveyQuestionOption> options;

Таким образом, вы по умолчанию выбираете здесь все дерево.

ТеперьКлючевым моментом здесь является то, что вы объявляете эти зависимости как List.Это означает упорядоченный, но разрешающий дубликаты.Здесь вы получите дублированный вопрос на число его вариантов.

Попробуйте использовать Set или SortedSet, чтобы избежать дублирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...