添加新成员时,Hibernate删除并重新插入ElementCollection的所有成员

时间:2018-12-18 11:49:14

标签: java hibernate hibernate-mapping

我正在尝试使用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();
}

UpvoteDownvoteVote的具体子类。这是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 HibernatehashCode()应该可以解决此问题,并指定不可空的列,以便将它们包括在主键约束中。但是,我已经完成了这两项工作,但是问题仍然存在。我已经测试了equals()equals()方法,以检查它们是否确实可以正常工作,是否可以正常工作。还有什么可能导致此行为?

编辑

当我使用一个带有hashCode()实现的Collection<>包时,也会发生同样的事情。这使我相信Hibernate会以某种方式编辑该集合。

0 个答案:

没有答案