我正在编写一个java spring Boot 后端,其中包含一个submitAnswers方法,该方法接受一个JSON数组,其中包含表示个性测验的问题和答案键的键值对,并为登录到后端的当前用户分配完整的个性得分。我编写了我的方法,以便如果当前用户有一个与其id相关联的score,那么我将删除表中现有的score对象(具有当前用户id)。但由于某种原因,如果当前登录的用户有一个与之关联的分数对象,我的代码不会删除分数条目。当我向submit-answers端点提交一个question-answers JSON数组时,在我的IntelliJ IDE中,我得到错误:java.sql.SQLIntegrityConstraintViolationException:关键字“score.user_entity_id”的重复条目“153”,其中153是当前用户的ID。
这是我的submitAnswers方法的代码
package com.wang.app.rest.Controller;
import com.wang.app.rest.Models.*;
import com.wang.app.rest.Repo.ScoreRepository;
import com.wang.app.rest.Repo.UserRepository;
import jakarta.annotation.PostConstruct;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.wang.app.rest.service.ScoreCalculationService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class QuizController {
@Autowired
private UserRepository userRepository;
@Autowired
private ScoreRepository scoreRepository;
@Autowired
private ScoreCalculationService scoreCalculationService; //inject the service into the controller
private Map<Integer, AnswerInfo> questionToMap = new HashMap<>();
//we use map interface type to make code more flexible...general map type
//if we wanna change to a different type of map, we can do that easily
//just change the right side of the assignment operator to a different type of map
//(1) Extraversion, (2) Agreeableness, (3) Conscientiousness, (4) Emotional Stability, or (5) Intellect/Imagination)
// and its direction of scoring (+ or -). These numbers should not be included in the actual survey questionnaire. For further information on scoring IPIP scales, click the following link:
//keys in the hash map are the question numbers, values are the answer info objects
@PostConstruct
//this postConstruct ensures questionToMap is initialized as soon as controller is created, before requests made
public void initQuestionToMap() {
questionToMap.put(1, new AnswerInfo(1, "+"));
questionToMap.put(2, new AnswerInfo(2, "-"));
questionToMap.put(3, new AnswerInfo(3, "+"));
questionToMap.put(4, new AnswerInfo(4, "-"));
questionToMap.put(5, new AnswerInfo(5, "+"));
questionToMap.put(6, new AnswerInfo(1, "-"));
questionToMap.put(7, new AnswerInfo(2, "+"));
questionToMap.put(8, new AnswerInfo(3, "-"));
questionToMap.put(9, new AnswerInfo(4, "+"));
questionToMap.put(10, new AnswerInfo(5, "-"));
questionToMap.put(11, new AnswerInfo(1, "+"));
questionToMap.put(12, new AnswerInfo(2, "-"));
questionToMap.put(13, new AnswerInfo(3, "+"));
questionToMap.put(14, new AnswerInfo(4, "-"));
questionToMap.put(15, new AnswerInfo(5, "+"));
questionToMap.put(16, new AnswerInfo(1, "-"));
questionToMap.put(17, new AnswerInfo(2, "+"));
questionToMap.put(18, new AnswerInfo(3, "-"));
questionToMap.put(19, new AnswerInfo(4, "+"));
questionToMap.put(20, new AnswerInfo(5, "-"));
questionToMap.put(21, new AnswerInfo(1, "+"));
questionToMap.put(22, new AnswerInfo(2, "-"));
questionToMap.put(23, new AnswerInfo(3, "+"));
questionToMap.put(24, new AnswerInfo(4, "-"));
questionToMap.put(25, new AnswerInfo(5, "+"));
questionToMap.put(26, new AnswerInfo(1, "-"));
questionToMap.put(27, new AnswerInfo(2, "+"));
questionToMap.put(28, new AnswerInfo(3, "-"));
questionToMap.put(29, new AnswerInfo(4, "+"));
questionToMap.put(30, new AnswerInfo(5, "-"));
questionToMap.put(31, new AnswerInfo(1, "+"));
questionToMap.put(32, new AnswerInfo(2, "-"));
questionToMap.put(33, new AnswerInfo(3, "+"));
questionToMap.put(34, new AnswerInfo(4, "-"));
questionToMap.put(35, new AnswerInfo(5, "+"));
questionToMap.put(36, new AnswerInfo(1, "-"));
questionToMap.put(37, new AnswerInfo(2, "+"));
questionToMap.put(38, new AnswerInfo(3, "-"));
questionToMap.put(39, new AnswerInfo(4, "+"));
questionToMap.put(40, new AnswerInfo(5, "-"));
questionToMap.put(41, new AnswerInfo(1, "+"));
questionToMap.put(42, new AnswerInfo(2, "-"));
questionToMap.put(43, new AnswerInfo(3, "+"));
questionToMap.put(44, new AnswerInfo(4, "-"));
questionToMap.put(45, new AnswerInfo(5, "+"));
questionToMap.put(46, new AnswerInfo(1, "-"));
questionToMap.put(47, new AnswerInfo(2, "+"));
questionToMap.put(48, new AnswerInfo(3, "-"));
questionToMap.put(49, new AnswerInfo(4, "+"));
questionToMap.put(50, new AnswerInfo(5, "-"));
}
//WHY IS THE return type map and not Hashmap
@PostMapping("/submit-answers")
@Transactional
public ResponseEntity<Score> submitAnswers(@RequestBody Map<Integer, Integer> answersData, @AuthenticationPrincipal CustomUserDetails customUserDetails) {
UserEntity currentUserEntity = customUserDetails.getUserEntity();
// If currentUserEntity is a new entity (not yet saved), save it first so it has an ID
if (currentUserEntity.getId() == null) {
userRepository.save(currentUserEntity);
} else if (currentUserEntity.getScore() != null) {
// Score oldScore = currentUserEntity.getScore();// Unlink from the score
// currentUserEntity.setScore(null); // Save the user entity without the score///should delete it all
// scoreRepository.delete(oldScore); // Delete old score from database
Score scoreRemove = scoreRepository.findById(currentUserEntity.getScore().getId()).get();
scoreRepository.delete(scoreRemove);
}
// Creating answer objects and associating them with the user
List<Answer> answers = new ArrayList<>();
for (Map.Entry<Integer, Integer> entry : answersData.entrySet()) {
Integer questionId = entry.getKey();
Integer answerValue = entry.getValue();
Answer answer = new Answer(questionId, answerValue);
answer.setUserEntity(currentUserEntity); // Associate the answer with the user
answers.add(answer); // Add the answer to the answers list
}
// Set answers for the user
currentUserEntity.setAnswers(answers);
// Calculating score based on answers
Score score = (scoreCalculationService.calculateScore(answers, questionToMap));//buggy still if i do score.setUsereNTTIY...
// score.setUserEntity(currentUserEntity);//the culprit here...
score.setUserEntity(currentUserEntity); // Set the relationship in the Score entity first
currentUserEntity.setScore(score);
currentUserEntity.setUsername(customUserDetails.getUsername());
// Associate the score with the user on both sides of the relationship
//if setting relationship in userentity first, then set into score....relationship might point to entity that hasnt been persistee dyet
// Save the user entity which should cascade the saves to Score and Answer
userRepository.save(currentUserEntity);
return ResponseEntity.ok(score);
}
}
以下是我的Score和UserEntity模型:
package com.wang.app.rest.Models;
import jakarta.persistence.*;
@Entity
public class Score {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "user_entity_id")
private UserEntity user;
//this is a foreign key
//should store the same value of userentity's id.
@Column
private int Extraversion;
@Column
private int Agreeableness;
private int Conscientiousness;
private int EmotionalStability;
private int Intellect;
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public int getExtraversion() {
return Extraversion;
}
public void setExtraversion(int extraversion) {
Extraversion = extraversion;
}
public int getAgreeableness() {
return Agreeableness;
}
public void setAgreeableness(int agreeableness) {
Agreeableness = agreeableness;
}
public int getConscientiousness() {
return Conscientiousness;
}
public void setConscientiousness(int conscientiousness) {
Conscientiousness = conscientiousness;
}
public int getEmotionalStability() {
return EmotionalStability;
}
public void setEmotionalStability(int emotionalStability) {
EmotionalStability = emotionalStability;
}
public int getIntellect() {
return Intellect;
}
public void setIntellect(int intellect) {
Intellect = intellect;
}
public UserEntity getUserEntity() {
return user;
}
@Override
public String toString() {
return "Score{" +
"extraversion=" + getExtraversion() +
", agreeableness=" + getAgreeableness() +
", conscientiousness=" + getConscientiousness() +
", emotionalStability=" + getEmotionalStability()+
", intellect=" +getIntellect() +
'}';
}
public void setUserEntity(UserEntity user) {
this.user = user;
}
}
package com.wang.app.rest.Models;
import jakarta.persistence.*;
import jdk.jfr.DataAmount;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.List;
@Table(name = "users")
@Data
@NoArgsConstructor
@Entity
public class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne
@JoinColumn(name="id")
@MapsId
private User user;
private String username;
private String password = "defaultPassword";
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) //want roles to be shown
//fetchtype eager: when we get user, we want to get roles as well
//cascade type all: if we delete user, we want to delete roles as well
@JoinTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
private List<Role> roles = new ArrayList<>();
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Answer> answers;
@OneToOne(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
//added cascadetype.all based on baeldung
private Score score;
public void setScore(Score score){
this.score = score;
}
}
我遵循了以下教程:
//https://www.geeksforgeeks.org/spring-data-jpa-delete-records-from-mysql/
从我的分数表中删除分数记录。
1条答案
按热度按时间hivapdat1#
您将mappedBy属性添加到UserEntity,这意味着现在它负责管理关系。
您可以通过将UserEntity的分数设置为null来删除分数。