经过大量搜索和尝试,在@marnish 和@Augusto 的帮助下,我找到了解决问题的方法。
我需要从我问错问题的问题开始,因为我想知道如何将这些数据实施到我的实体中,而这种思维方式导致我在寻找解决方案时遇到很多麻烦,因为这仅限于我能够实现的目标。最好将我的数据库对象与我的 JSON 对象分开,因为一个用于持久化数据,另一个用于呈现给客户端,而第一种方式几乎不链接到数据库列。瞬态属性对我来说也不是解决方案。
意识到(并接受)这一点,下一个问题是让新的表示对象与页面包装器很好地配合使用,因为我的问题需要分页。这是我写的解决方案:
问题作为链接到数据库表和列的实体
@Entity
@Table(name = "vragen")
// BaseEntity just contains the ID property
public class Question extends BaseEntity {
@Column(name = "vraag")
private String question;
@Column(name = "bericht")
private String message;
@ManyToOne
@JoinColumn(name = "gebruiker")
private User user;
@Column(name = "beantwoord", insertable = false)
private boolean answered;
@Column(name = "gepost_op", insertable = false)
private Timestamp postedOn;
@Column(name = "actief", insertable = false)
@JsonIgnore
private boolean active;
@Column(name = "bekeken", insertable = false, updatable = false)
private int viewed;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "vragen_tags",
joinColumns = @JoinColumn(name = "vraag_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "tag_id", referencedColumnName = "id"))
private Set<Tag> tags;
@OneToMany(mappedBy = "question")
// Thanks to @manish we can do it more efficiently instead of loading all the Answer objects
@LazyCollection(LazyCollectionOption.EXTRA)
@JsonManagedReference
private Set<Answer> answers;
public Question() {}
// getters and setters
}
QuestionDTO 作为 JSON 表示对象
public class QuestionDTO {
private Integer id;
private String question;
private String message;
private User user;
private boolean answered;
private Timestamp postedOn;
private int viewed;
private Set<Tag> tags;
private int totalAnswers;
public QuestionDTO() {}
// getters and setters
}
QuestionServiceImpl 中的方法:
public Page<QuestionDTO> getAllQuestions(int page, int size, String filter) {
List<QuestionDTO> questions = new ArrayList<>();
Page<Question> questionPage;
switch (filter) {
case "popular":
questionPage = questionRepository.findAllByActiveTrueOrderByViewedDescPostedOnDesc(PageRequest.of(page, size));
break;
case "answered":
questionPage = questionRepository.findAllByActiveTrueAndAnsweredTrueOrderByPostedOnDesc(PageRequest.of(page, size));
break;
default:
questionPage = questionRepository.findAllByActiveTrueOrderByPostedOnDesc(PageRequest.of(page, size));
break;
}
// Here the entity data is being converted to the presentation DTO. I'm sure this can be done cleaner with for example Mapstruct as objectmapper.
for (Question q : questionPage) {
QuestionDTO questionDTO = new QuestionDTO();
questionDTO.setId(q.getId());
questionDTO.setQuestion(q.getQuestion());
questionDTO.setMessage(q.getMessage());
questionDTO.setUser(q.getUser());
questionDTO.setAnswered(q.isAnswered());
questionDTO.setPostedOn(q.getPostedOn());
questionDTO.setViewed(q.getViewed());
questionDTO.setTags(q.getTags());
questionDTO.setTotalAnswers(q.getAnswers().size());
questions.add(questionDTO);
}
// We want to keep all the pagination data that the method returned, so we need to wrap the questionDTO in a Page wrapper and pass all the data from Page<Question>
return new PageImpl<>(questions, questionPage.getPageable(), questionPage.getTotalElements());
}
回答实体:
@Entity
@Table(name = "antwoorden")
public class Answer extends BaseEntity {
@Column(name = "bericht")
private String message;
@ManyToOne
@JoinColumn(name = "gebruiker")
private User user;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "vraag")
@JsonBackReference
private Question question;
@Column(name = "gepost_op", insertable = false)
private Timestamp postedOn;
@Column(name = "actief", insertable = false)
private boolean active;
public Answer() {}
// getters and setters
}