Problem z metodą do aktualizacji w Spring boot

0

Hej powiem mi ktoś co robię źle i jak to mam zrobić bo już nie wiem całkiem coś pokręciłem. Mam metode do aktualizacji pytania i odpowiedzi quizu.
Pytanie sie aktualizuje a odpowiedzi i nie wiem czemu.

 public void updateQuestions(Long questionId, Questions questions, Principal principal) {
        String username = principal.getName();
        User user = userRepository.findByEmail(username).orElseThrow(() -> new EntityNotFoundException("Not found user"));

        Questions questionToUpdate = questionsRepository.findById(questionId).orElseThrow(() -> new EntityNotFoundException("Question not found"));

        Quiz quiz = questionToUpdate.getQuiz();
        if (quiz == null || !quiz.getUserId().equals(user.getId())) {
            throw new UnsupportedOperationException("You are not authorized to update this question");
        }
        
        questionToUpdate.setContents(questions.getContents());
        for (Answers answer : questionToUpdate.getAnswers()) {
            answer.setQuestion(questionToUpdate);
            for (Answers updatedAnswer : questions.getAnswers()) {
                if (answer.getId().equals(updatedAnswer.getId())) {
                    answer.setContents(updatedAnswer.getContents());
                }
            }
        }
        
        questionsRepository.save(questionToUpdate);
    }

@Entity
@Data
public class Questions {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String contents;
    @ManyToOne
    @JoinColumn(name = "quiz_id")
    private Quiz quiz;
    @OneToMany(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Answers> answers = new ArrayList<>();
}
1
  1. Pokaż jeszcze jak wygląda encja Answersoraz Quiz (to drugie z ciekawości)
  2. Opisz słowami co według Ciebie powinno się tutaj zadziać:
 questionToUpdate.setContents(questions.getContents());
        for (Answers answer : questionToUpdate.getAnswers()) {
            answer.setQuestion(questionToUpdate);
            for (Answers updatedAnswer : questions.getAnswers()) {
                if (answer.getId().equals(updatedAnswer.getId())) {
                    answer.setContents(updatedAnswer.getContents());
                }
            }
        }
  1. W klasie dotyczącej pytania trzymasz cały Quiz? Na pewno chcesz tak robić? Nie lepiej zostawić tam samo idQuizu?
  2. Nazywaj klasy w liczbie pojedyńczej.
Questions questionToUpdate = questionsRepository.findById(questionId).orElseThrow(() -> new EntityNotFoundException("Question not found"));

Nie uważasz ze wygląda to dziwnie? Nazywasz obiekt questionToUpdate, a nazwa klasy to Questions?

0
kixe52 napisał(a):
  1. Pokaż jeszcze jak wygląda encja Answersoraz Quiz (to drugie z ciekawości)
  2. Opisz słowami co według Ciebie powinno się tutaj zadziać:
 questionToUpdate.setContents(questions.getContents());
        for (Answers answer : questionToUpdate.getAnswers()) {
            answer.setQuestion(questionToUpdate);
            for (Answers updatedAnswer : questions.getAnswers()) {
                if (answer.getId().equals(updatedAnswer.getId())) {
                    answer.setContents(updatedAnswer.getContents());
                }
            }
        }
  1. W klasie dotyczącej pytania trzymasz cały Quiz? Na pewno chcesz tak robić? Nie lepiej zostawić tam samo idQuizu?
  2. Nazywaj klasy w liczbie pojedyńczej.
Questions questionToUpdate = questionsRepository.findById(questionId).orElseThrow(() -> new EntityNotFoundException("Question not found"));

Nie uważasz ze wygląda to dziwnie? Nazywasz obiekt questionToUpdate, a nazwa klasy to Questions?

@Entity
@Data
public class Quiz {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long userId;
    private String title;

    @ManyToOne
    private Category category;

    @OneToMany(mappedBy = "quiz", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Questions> questions;
    private Status status;
}

@Entity
@Data
public class Answers {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String contents;
    private boolean correct;
    @ManyToOne
    @JoinColumn(name="questions_id")
    private Questions question;
}
  1. No to tak:
    treść znalezionego pytanie aktualizuje czyli ustawiam na takie jakie podam w json
    potem pętla for żeby przez każdą odp przejść która należy do pytania i ustawiamy te odpowiedzi do tego pytania( co jest chyba niepotrzebne bo jest to zrobione przy dodawaniu pytania)
    nastepny for to sprawdzanie czy odp nalezy do pytania jesli tak to tresc answer ustawiamy na nową podaną w json.
    Tak to rozumiem
    questionToUpdate.setContents(questions.getContents());
    for (Answers answer : questionToUpdate.getAnswers()) {
    answer.setQuestion(questionToUpdate);
    for (Answers updatedAnswer : questions.getAnswers()) {
    if (answer.getId().equals(updatedAnswer.getId())) {
    answer.setContents(updatedAnswer.getContents());
    }
    }
    }
  2. W sumie racja moze byc dame id bo na tym mi zależy
  3. Racja
    Nie uważasz ze wygląda to dziwnie? Nazywasz obiekt questionToUpdate, a nazwa klasy to Questions?
    Może nie najlepsza nazwa ale no szukam obiektu który bede aktualizował.
0

Czy możesz opisać biznesowo / z perspektywy użytkownika co ma na celu ta aktualizacja z punktu 2? Kiedy to się będzie działo?
Czy możesz pokazać przykładowe dane przed i po operacji? Co oczekujesz, że się zadzieje?

0
kixe52 napisał(a):

Czy możesz opisać biznesowo / z perspektywy użytkownika co ma na celu ta aktualizacja z punktu 2? Kiedy to się będzie działo?
Czy możesz pokazać przykładowe dane przed i po operacji? Co oczekujesz, że się zadzieje?

Nie bardzo rozumiem. Na celu ma to, że jeśli użytkownik stworzył quiz ale później chce go poprawić, coś zmienić to to robi bez tworzenia od nowa. Po użyciu tej metody zmienia się tylko treść pytania a odpowiedzi zostają bez zmian.

1

Zgaduje.
Jedna z opcji to (nie wiem czy najlepsza):
krok 1: dodaj @Transacional do metody.
krok 2: wywal to questionsRepository.save(questionToUpdate);

Jak nie pomoże to sprawdź czy tak np. if z porównymaniem id (na Answer)w ogóle łapie coś (jakiś println wrzuć - czy coś).

0
jarekr000000 napisał(a):

Zgaduje.
Jedna z opcji to (nie wiem czy najlepsza):
krok 1: dodaj @Transacional do metody.
krok 2: wywal to questionsRepository.save(questionToUpdate);

Jak nie pomoże to sprawdź czy tak np. if z porównymaniem id (na Answer)w ogóle łapie coś (jakiś println wrzuć - czy coś).

Krok 1 nie pomógł
Krok 2 nie bardzo rozumiem co to zmieni wtedy to juz pytanie sie nie bedzie aktualizować
Sprawdziłem i id question w answer jest dobre

1
LukaszCh233 napisał(a):

Krok 2 nie bardzo rozumiem co to zmieni wtedy to juz pytanie sie nie bedzie aktualizować

A sprawdziłeś?
Tak naprawdę to ten save co najwyżej nie przeszkadza (jak masz ten @Transactional), ale jest zupełnie do niczego nie potrzebny.

Na tym etapie popatrzyłbym w logi:
https://www.baeldung.com/sql-logging-spring-boot

może tam coś będzie ciekawego (jakie SQLe idą, jakie warningi itp.).

0

A jakby tak po prostu usunąć stare odpowiedzi i dodać nowe zamiast je podmieniać?

1
LukaszCh233 napisał(a):

A jakby tak po prostu usunąć stare odpowiedzi i dodać nowe zamiast je podmieniać?

Oczywiście, możesz spróbować.
Pytanie czy powinieneś w ogóle pracować z technologią, która jest dla Ciebie magiczna?
Technicznie na pewno jest proste wyjaśnienie dlaczego ten kod wyżej nie działał - natomiast bez całości kodu nie jestem tego w stanie zgadnąć.
I ogólnie jeśli jednak zamierzasz kontynuować przykrą znajomość ze springiem to warto, żebyś to wyjaśnił. Inaczej będziesz tak co chwila robiłe workaroundy, zmieniał kolejnościa linijki i liczył, że w końcu zadziała. (aczkolwiek znam trochę seniorów springa, którzy tak właśnie robią - najczęściej sprawdza się losowe dodawanie adnotacji).

0

Trochę to zmodyfikowałem i jest mniejszy bałagan chyba.

 public void updateQuestion(Long quizId, Long questionId, Question question, Principal principal) {
        String username = principal.getName();
        User user = userRepository.findByEmail(username).orElseThrow(() -> new EntityNotFoundException("Not found user"));

        Quiz quiz = quizRepository.findById(quizId).orElseThrow(() -> new EntityNotFoundException("Quiz not found"));

        if (!quiz.getUserId().equals(user.getId())) {
            throw new UnsupportedOperationException("User is not authorized to delete this quiz");
        }
        Question questionToUpdate = questionsRepository.findById(questionId).orElseThrow(() -> new EntityNotFoundException("Not found"));

        questionToUpdate.setContent(question.getContent());

        questionToUpdate.getAnswers().clear();

        for (Answer answer : question.getAnswers()) {
            answer.setQuestion(questionToUpdate);
            questionToUpdate.getAnswers().add(answer);
        }

        questionsRepository.save(questionToUpdate);
    }

1 użytkowników online, w tym zalogowanych: 0, gości: 1