<分区>
我正在使用 Hibernate 和 DTO 来保存我的实体,它们是 Test (tests)
、TestQuestion (test_questions)
和 TestAnswer (test_answers)
.
我使用 ModelMaper 将 DTO 转换为 Hibernate 实体.我的实体保存错误:
1) 第一个问题是我在映射完成后在测试实体中设置了 User
对象。 JPA 在 tests
表中创建了 2 个实体。一个有用户 ID,一个没有用户 ID。 Test
类中的Question
列表正确保存在test_questions
表中,引用用户id为空的test id。
2) 第二个问题是 Question
类中的 Answer
列表根本没有保存在 test_answers
表中。
表格:
SQL 表:
CREATE TABLE tests (
id UUID DEFAULT uuid_generate_v4 () PRIMARY KEY,
therapist_id UUID REFERENCES users (id) ON DELETE CASCADE ON UPDATE CASCADE,
description TEXT DEFAULT NULL,
level INTEGER NOT NULL,
active BOOLEAN DEFAULT FALSE,
date_time_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
date_time_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE test_questions (
id UUID DEFAULT uuid_generate_v4 () PRIMARY KEY,
test_id UUID NOT NULL REFERENCES tests (id) ON DELETE CASCADE ON UPDATE CASCADE,
type TEST_TYPE_ENUM NOT NULL,
question TEXT NOT NULL,
audio TEXT DEFAULT NULL,
description TEXT DEFAULT NULL,
img TEXT NOT NULL,
cloud_id TEXT NOT NULL,
date_time_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
date_time_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE test_answers (
id UUID DEFAULT uuid_generate_v4 () PRIMARY KEY,
question_id UUID NOT NULL REFERENCES test_questions (id) ON DELETE CASCADE ON UPDATE CASCADE,
answer TEXT NOT NULL,
audio TEXT DEFAULT NULL,
img TEXT DEFAULT NULL,
cloud_id TEXT NOT NULL,
date_time_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
date_time_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
测试类:
@Entity
@Table(name = "tests")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Test implements Serializable {
private static final long serialVersionUID = -2184376232517605961L;
@Id
@GeneratedValue(generator = "uuid2", strategy = GenerationType.SEQUENCE)
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Type(type = "pg-uuid")
private UUID id;
private String description;
private Integer level = 0;
private Boolean active = false;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "date_time_created")
@JsonIgnore
private Date dateTimeCreated = new Date();
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "date_time_updated")
@JsonIgnore
private Date dateTimeUpdated = new Date();
@ManyToOne(fetch = FetchType.LAZY)
@JsonBackReference
@JoinColumn(name = "therapist_id")
private User user;
@OneToMany(mappedBy = "test", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<TestQuestion> questions = new HashSet<>();
// getters-setters
@Override
public String toString() {
return "Test{" +
"id=" + id +
", description='" + description + '\'' +
", level=" + level +
", active=" + active +
", dateTimeCreated=" + dateTimeCreated +
", dateTimeUpdated=" + dateTimeUpdated +
", user=" + user.getId() +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Test test = (Test) o;
return Objects.equal(id, test.id) &&
Objects.equal(description, test.description) &&
Objects.equal(level, test.level) &&
Objects.equal(active, test.active) &&
Objects.equal(dateTimeCreated, test.dateTimeCreated) &&
Objects.equal(dateTimeUpdated, test.dateTimeUpdated) &&
Objects.equal(user, test.user) &&
Objects.equal(questions, test.questions);
}
@Override
public int hashCode() {
return Objects.hashCode(id, description, level, active, dateTimeCreated, dateTimeUpdated, user, questions);
}
}
TestQuestion 类:
@Entity
@Table(name = "test_questions")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class TestQuestion implements Serializable {
private static final long serialVersionUID = 6367504273687746576L;
@Id
@GeneratedValue(generator = "uuid2", strategy = GenerationType.SEQUENCE)
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Type(type = "pg-uuid")
private UUID id;
private String question;
private String description;
@Enumerated(EnumType.ORDINAL)
@Type(type = "pgsql_enum")
private TestQuestionTypeEnum type;
private String img;
private String audio;
private String cloudId;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "date_time_created")
@JsonIgnore
private Date dateTimeCreated = new Date();
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "date_time_updated")
@JsonIgnore
private Date dateTimeUpdated = new Date();
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = "test_id")
private Test test;
@OneToMany(mappedBy = "question", fetch = FetchType.EAGER)
private Set<TestAnswer> answers = new HashSet<>();
// getters-setters
@Override
public String toString() {
return "TestQuestion{" +
"id=" + id +
", question='" + question + '\'' +
", description='" + description + '\'' +
", type=" + type +
", img='" + img + '\'' +
", audio='" + audio + '\'' +
", cloudId='" + cloudId + '\'' +
", dateTimeCreated=" + dateTimeCreated +
", dateTimeUpdated=" + dateTimeUpdated +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TestQuestion that = (TestQuestion) o;
return Objects.equal(id, that.id) &&
Objects.equal(question, that.question) &&
Objects.equal(description, that.description) &&
type == that.type &&
Objects.equal(img, that.img) &&
Objects.equal(audio, that.audio) &&
Objects.equal(cloudId, that.cloudId) &&
Objects.equal(dateTimeCreated, that.dateTimeCreated) &&
Objects.equal(dateTimeUpdated, that.dateTimeUpdated) &&
Objects.equal(test, that.test) &&
Objects.equal(answers, that.answers);
}
@Override
public int hashCode() {
return Objects.hashCode(id, question, description, type, img, audio, cloudId, dateTimeCreated, dateTimeUpdated, test, answers);
}
}
TestAnswer 类:
@Entity
@Table(name = "test_answers")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class TestAnswer implements Serializable {
private static final long serialVersionUID = -2372807870272293491L;
@Id
@GeneratedValue(generator = "uuid2", strategy = GenerationType.SEQUENCE)
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Type(type = "pg-uuid")
private UUID id;
private String answer;
private String audio;
private String img;
private String cloudId;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "date_time_created")
@JsonIgnore
private Date dateTimeCreated = new Date();
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "date_time_updated")
@JsonIgnore
private Date dateTimeUpdated = new Date();
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JsonBackReference
@JoinColumn(name = "question_id")
private TestQuestion question;
// getters-setters
@Override
public String toString() {
return "TestAnswer{" +
"id=" + id +
", answer='" + answer + '\'' +
", audio='" + audio + '\'' +
", img='" + img + '\'' +
", cloudId='" + cloudId + '\'' +
", dateTimeCreated=" + dateTimeCreated +
", dateTimeUpdated=" + dateTimeUpdated +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TestAnswer that = (TestAnswer) o;
return Objects.equal(id, that.id) &&
Objects.equal(answer, that.answer) &&
Objects.equal(audio, that.audio) &&
Objects.equal(img, that.img) &&
Objects.equal(cloudId, that.cloudId) &&
Objects.equal(dateTimeCreated, that.dateTimeCreated) &&
Objects.equal(dateTimeUpdated, that.dateTimeUpdated) &&
Objects.equal(question, that.question);
}
@Override
public int hashCode() {
return Objects.hashCode(id, answer, audio, img, cloudId, dateTimeCreated, dateTimeUpdated, question);
}
}
服务类:
@Component("testService")
@Transactional
public class TestService extends Helper {
private static final Logger log = LoggerFactory.getLogger(TestService.class);
private final TestRepository testRepository;
private final UserService userService;
private final ModelMapper modelMapper;
public TestService(TestRepository testRepository, UserService userService, ModelMapper modelMapper) {
this.testRepository = testRepository;
this.userService = userService;
this.modelMapper = modelMapper;
}
public Test createTest(TestDTO testDTO) {
User teacher = userService.findById(getLoggedUserId());
Test test = toTest(testDTO, modelMapper);
test.setUser(teacher);
test = testRepository.saveAndFlush(test);
return test;
}
private Test toTest(TestDTO testDTO, ModelMapper modelMapper) {
Test test = new Test();
Set<TestQuestion> testQuestions = new LinkedHashSet<>();
TestValidity.validate(testDTO);
testDTO.getQuestions().forEach(q -> {
TestQuestion question = toQuestion(q, modelMapper);
Set<TestAnswer> answers = toAnswerSet(q.getAnswers(), modelMapper);
question.setAnswers(answers);
testQuestions.add(question);
});
test.setQuestions(testQuestions);
return test;
}
private TestQuestion toQuestion(TestQuestionDTO questionDTO, ModelMapper modelMapper) {
return modelMapper.map(questionDTO, TestQuestion.class);
}
private Set<TestAnswer> toAnswerSet(Set<TestAnswerDTO> answerDTOSet, ModelMapper modelMapper) {
Set<TestAnswer> answers = new HashSet<>();
answerDTOSet.forEach(a -> {
TestAnswer answer = modelMapper.map(a, TestAnswer.class);
answers.add(answer);
});
return answers;
}
有什么我想念的吗?我不确定这些问题是否是因为 `ModelMapper,因为这是我第一次使用它。如何正确保存我的实体?