Hibernate удаляет и повторно вставляет все элементы ElementCollection при добавлении нового члена - PullRequest
0 голосов
/ 18 декабря 2018

Я пытаюсь создать демонстрационное приложение вопросов и ответов, используя 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 с именем VoteType, и полиморфизм работает, протестированный с использованием метода getScore().

Однако всякий раз, когда я добавляю новый голос в коллекцию votes, Hibernate удаляет, а затем заново вставляет все голоса по одному.Поиски в Google и Java Persistence with Hibernate предполагают, что переопределение hashCode() и equals() должно решить эту проблему, а также указание столбцов как необнуляемых, чтобы они были включены в ограничение первичного ключа.Но я сделал обе эти вещи, и все же проблема все еще остается.Я протестировал методы equals() и hashCode(), чтобы проверить, действительно ли они работают правильно, что они и делают.Что еще может быть причиной такого поведения?

Edit

То же самое происходит, когда я использую сумку, Collection<> с реализацией ArrayList<>.Это заставляет меня поверить, что Hibernate видит коллекцию как-то отредактированной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...