我正在尝试使用Spring Boot,Hibernate和PostgreSQL创建一个演示问答应用程序。我有一个Question
个@ElementCollection
的类Vote
。这是Vote.java
的定义:
@MappedSuperclass
public abstract class Vote implements Serializable {
protected enum VoteDirection {
UP("UP"), DOWN("DOWN");
private String text;
VoteDirection(String text) {
this.text = text;
}
public String toString() {
return text;
}
}
public static Vote fromString(String userID, String voteDirection) {
if (voteDirection.equals(VoteDirection.UP.toString())) {
return upvote(UUID.fromString(userID));
} else if (voteDirection.equals(VoteDirection.DOWN.toString())) {
return downvote(UUID.fromString(userID));
} else {
throw new IllegalArgumentException("Unsupported String format: " + voteDirection);
}
}
public static Vote upvote(UUID userID) {
return new Upvote(userID);
}
public static Vote downvote(UUID userID) {
return new Downvote(userID);
}
@Type(type = "uuid-char")
@Column(name = "userid", nullable = false)
private UUID userID;
public Vote() {
}
public Vote(UUID userID) {
this.userID = userID;
}
@Enumerated(value = EnumType.STRING)
@Column(name = "type")
protected VoteDirection type;
public UUID getUserID() {
return userID;
}
public String getType() {
return type.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
Vote vote = (Vote) o;
return getUserID().toString().equals(vote.getUserID().toString());
}
@Override
public int hashCode() {
return getUserID().toString().hashCode();
}
public abstract Integer getScore();
}
Upvote
和Downvote
是Vote
的具体子类。这是Question
的定义:
@Entity
@Table(name = "questions")
@org.hibernate.annotations.TypeDef(name = "vote_type", typeClass = VoteType.class)
public class Question extends AuditModel {
@Id
@GeneratedValue(generator = "UUID")
@org.hibernate.annotations.GenericGenerator(
name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator"
)
private UUID id;
@NotBlank
@Size(min = 3, max = 100)
private String title;
@Column(columnDefinition = "text")
private String description;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "question")
@JsonIgnore
private Set<Answer> answers = new HashSet<>();
@org.hibernate.annotations.Type(type = "vote_type")
@org.hibernate.annotations.Columns(columns = {
@Column(name = "userid", nullable = false),
@Column(name = "type", nullable = false)
})
@ElementCollection(fetch = FetchType.LAZY)
private Set<Vote> votes = new HashSet<>();
public Set<Answer> getAnswers() {
return answers;
}
public UUID getId() {
return id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Set<Vote> getVotes() {
return Collections.unmodifiableSet(votes);
}
public void upvote(UUID userID) {
votes.add(new Upvote(userID));
}
public void downvote(UUID userID) {
votes.add(Vote.downvote(userID));
}
public Integer getScore() {
return votes.stream().mapToInt(Vote::getScore).sum();
}
}
为了支持@ElementCollection
多态性,我创建了一个名为CompositeUserType
的{{1}},使用VoteType
方法进行了测试,多态性确实有效。
但是,每当我在getScore()
集合中添加新的投票时,Hibernate都会删除并重新插入所有投票。 Google搜索和votes
建议重写Java Persistence with Hibernate
和hashCode()
应该可以解决此问题,并指定不可空的列,以便将它们包括在主键约束中。但是,我已经完成了这两项工作,但是问题仍然存在。我已经测试了equals()
和equals()
方法,以检查它们是否确实可以正常工作,是否可以正常工作。还有什么可能导致此行为?
当我使用一个带有hashCode()
实现的Collection<>
包时,也会发生同样的事情。这使我相信Hibernate会以某种方式编辑该集合。