在多人关系的测验中添加问题

ybzsozfc  于 2021-06-26  发布在  Java
关注(0)|答案(2)|浏览(273)

我有一个 Many-To-Many relationship 介于 Quiz 表和a Question table。我想问的是,我是如何得到逻辑下来,能够添加一个问题到一个测验的测验id,所以我可以链接到一个特定的测验多个问题。
测验实体侧

@ManyToMany(fetch = FetchType.EAGER, cascade = {
    CascadeType.MERGE
})
@JoinTable(name = "quiz_content", 
           joinColumns = @JoinColumn(name = "quiz_id"), 
           inverseJoinColumns = @JoinColumn(name = "question_id")
)
private List<Question> questions = new ArrayList<>();

问题实体方

@ManyToMany(mappedBy = "questions")
private List<Quiz> quizList = new ArrayList<>();

这是我的控制器:

@PostMapping(value = "/add")
public String addQuestionToQuiz(Quiz quiz, BindingResult bindingResult, Model model) {

       return "quiz/index";
    }

我如何在注解中实现逻辑,因为当我实现时,它会抛出如下错误:

invalid property of bean class cannot get element with index 0 from set of size 0, accessed using property path.
qhhrdooz

qhhrdooz1#

你应该使用 Set 而不是 List . 在这种情况下不应该使用级联。我在下面添加了一个带有测试类的实现,您可以在其中看到如何添加 Question 示例到 Quiz 示例。
问题类

package no.mycompany.myapp.misc;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import java.util.HashSet;
import java.util.Set;

@Entity
@Getter
@Setter
public class Question {

    @Id
    @GeneratedValue
    private long id;

    @ManyToMany(mappedBy = "questions")
    private Set<Quiz> quizList = new HashSet<>();
}

问题VM类

package no.mycompany.myapp.misc;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
public class QuestionVM {

    private long id;

    // TODO add remaining fields except for collections containing Quiz instances

    public QuestionVM(Question question) {
        this.id = question.getId();

        // TODO init remaining fields
    }
}

问题报告

package no.mycompany.myapp.misc;

import org.springframework.data.jpa.repository.JpaRepository;

public interface QuestionRepo extends JpaRepository<Question, Long> { }

测验课

package no.mycompany.myapp.misc;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Getter
@Setter
@Entity
public class Quiz {

    @Id
    @GeneratedValue
    private long id;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "quiz_content",
            joinColumns = @JoinColumn(name = "quiz_id"),
            inverseJoinColumns = @JoinColumn(name = "question_id")
    )
    private Set<Question> questions = new HashSet<>();

    public void addQuestion(Question question) {
        question.getQuizList().add(this);
        questions.add(question);
    }

    public void removeQuestion(Question question) {
        question.getQuizList().remove(this);
        questions.remove(question);
    }
}

快进班

package no.mycompany.myapp.misc;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Getter
@Setter
@NoArgsConstructor
public class QuizVM {

    private long id;
    private List<QuestionVM> questions = new ArrayList<>();

    // TODO add remaining fields

    public QuizVM(Quiz quiz) {
        this.id = quiz.getId();
        this.questions = quiz.getQuestions().stream().map(QuestionVM::new).collect(Collectors.toList());

        // TODO init remaining fields
    }
}

奎兹雷波

package no.mycompany.myapp.misc;

import org.springframework.data.jpa.repository.JpaRepository;

public interface QuizRepo extends JpaRepository<Quiz, Long> { }

奎兹雷波试验

package no.mycompany.myapp.misc;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.ActiveProfiles;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

@ActiveProfiles("test")
@DataJpaTest
public class QuizRepoTest {

    @Autowired
    TestEntityManager testEntityManager;

    @Autowired
    QuizRepo quizRepo;

    @Autowired
    QuestionRepo questionRepo;

    @Test
    public void test() {
        var quizInDb = new Quiz();
        var question1InDb = questionRepo.save(new Question());
        var question2InDb = questionRepo.save(new Question());

        quizInDb.addQuestion(question1InDb);
        quizInDb.addQuestion(question2InDb);

        quizInDb = quizRepo.save(quizInDb);

        // verify that Quiz instance has 2 questions
        var quiz = testEntityManager.find(Quiz.class, quizInDb.getId());
        assertThat(quiz.getQuestions().size()).isEqualTo(2);

        // verify that question #1 has 1 Quiz instance
        var question1 = testEntityManager.find(Question.class, question1InDb.getId());
        assertThat(question1.getQuizList().size()).isEqualTo(1);

        // remove question #1 from Quiz instance
        quizInDb = quizRepo.getOne(quiz.getId());
        question1InDb = questionRepo.getOne(question1.getId());
        quizInDb.removeQuestion(question1InDb);
        quizRepo.save(quizInDb);

        // verify that Quiz instance has 1 question
        quiz = testEntityManager.find(Quiz.class, quiz.getId());
        assertThat(quiz.getQuestions().size()).isEqualTo(1);

        // verify that question #1 has 0 Quiz instances
        question1 = testEntityManager.find(Question.class, question1InDb.getId());
        assertThat(question1.getQuizList().size()).isEqualTo(0);

        questionRepo.delete(question1InDb);

        // verify that question #1 is deleted from db
        assertThat(testEntityManager.find(Question.class, question1InDb.getId())).isNull();

        quizInDb = quizRepo.getOne(quiz.getId());
        question2InDb = quizInDb.getQuestions().stream().findFirst().orElse(null);
        question2InDb.setComment("test");
        quizRepo.save(quizInDb);

        var question2 = testEntityManager.find(Question.class, question2InDb.getId());
        assertThat(question2.getComment()).isEqualTo("test");
    }
}

quizservice类

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class QuizService {

    private final QuizRepo quizRepo;
    private final QuestionRepo questionRepo;

    public void saveQuiz(QuizVM quiz) {

        var quizInDb = quiz.getId() > 0 ? quizRepo.getOne(quiz.getId()) : new Quiz();
        // TODO: Copy updated fields from QuizVM instance to quizInDb

        // remove deleted questions
        quizInDb.getQuestions().removeAll(
                quizInDb.getQuestions().stream()
                        .filter(questionInDb -> quiz.getQuestions().stream().noneMatch(it -> questionInDb.getId() == it.getId()))
                        .collect(Collectors.toSet()));

        quiz.getQuestions().forEach(questionVM ->  {
            var currentQuestionInDb = quizInDb.getQuestions()
                    .stream()
                    .filter(it -> it.getId() == questionVM.getId())
                    .findFirst()
                    .orElse(new Question());

            // TODO: Copy updated fields from QuestionVM instance to currentQuestion

            if (currentQuestionInDb.getId() < 1) {
                questionRepo.save(currentQuestionInDb);
                quizInDb.addQuestion(currentQuestionInDb);
            }
        });

        quizRepo.save(quizInDb);
    }
}

控制器方法

@PostMapping(value = "/add")
public String addQuestionToQuiz(QuizVM quiz, BindingResult bindingResult, Model model) {

   return "quiz/index";
}
umuewwlo

umuewwlo2#

这是一种双向关系,因此需要使用自定义方法处理添加或删除操作,以避免任何不可预知的错误。您应该添加一个自定义 addQuestion() 方法,即 Quiz 实体。

@Entity
public class Quiz {
    //...
    public void addQuestion(Question question) {
        questions.add(question);
        question.getQuizList().add(this);
    }
    //...
}

然后你可以在测验中添加一个问题:

Question question = new Question();
questionRepository.save(question);

Quiz quiz = quizRepository.findById(quizId).get();
quiz.addQuestion(question);
quizRepository.save(quiz);

ps:我建议你使用 Set 而不是 List@ManyToMany 为了更好的表现。

相关问题