Вопрос

Предположим, что такое отображение

@Entity
public class User {

    private Integer id

    private List<Info> infoList;    

    @Id
    public getId() {
        return this.id;
    }

    @OneToMany(cascade=CascadeType.ALL)
    @JoinColumn(name="USER_ID", insertable=false, updateable=false, nullable=false)
    public getInfoList() {
        return this.infoList;
    }

    public void addQuestion(Info question) {
        info.setInfoCategory(InfoCategory.QUESTION);
        info.setInfoId(new InfoId(getId(), getInfoList().size()));

        getInfoList().add(question);
    }

    public void addAnswer(InfoRepository repository, Integer questionIndex, Info answer) {
        Info question = repository.getInfoById(new InfoId(getId(), questionIndex));

        if(question.getInfoCategory().equals(InfoCategory.ANSWER))
            throw new RuntimeException("Is not a question");

        if(question.getAnswer() != null)
            throw new RuntimeException("You can not post a new answer");

        answer.setInfoCategory(InfoCategory.ANSWER);
        answer.setInfoId(new InfoId(getId(), getInfoList().size()));

        getInfoList().add(answer);

        question.setAnswer(answer);
    }

}

И вопрос и ответ, сопоставленные классом Info.

@Entity
public class Info implements Serializable {

    private InfoId infoId;

    private Info answer;

    private InfoCategory infoCategory;

    public Info() {}

    @Embeddable
    public static class InfoId {

        private Integer userId;
        private Integer index;

        public InfoId(Integer userId, Integer index) {
            this.userId = userId;
            this.index = index;
        }

        @Column("USER_ID", updateable=false, nullable=false)
        public getUserId() {
            return this.userId;
        } 

        @Column("INFO_INDEX", updateable=false, nullable=false)
        public getIndex() {
            return this.index;
        }

        // equals and hashcode

    }

    // mapped as a ManyToOne instead of @OneToOne
    @ManyToOne
    JoinColumns({
        JoinColumn(name="USER_ID", referencedColumnName="USER_ID", insertable=false, updateable=false),
        JoinColumn(name="ANSWER_INDEX", referencedColumnName="INFO_INDEX", insertable=false)
    })
    public Info getAnswer() {
        return this.answer;  
    }

    @EmbeddedId
    public InfoId getInfoId() {
        return this.infoId;
    }

}

В getAnswer я использую ManyToOne вместо OneToOne, поскольку некоторые проблемы связаны с сопоставлением OneToOne.OneToOne можно сопоставить как ManyToOne (unique=true в @JoinColumn).INFO_INDEX не имеет отношения к какой-либо конкретной цели.Просто ключ для поддержки составного первичного ключа в СТАРОЙ системе.

Прежде чем ответить, обратите внимание на следующее:

Если объекту присвоен идентификатор или составной ключ, идентификатор ДОЛЖЕН БЫТЬ НАЗНАЧЕН экземпляру объекта ПЕРЕД вызовом метода save().

Поэтому мне нужно составить карту JoinColumn(name="USER_ID", referencedColumnName="USER_ID", Insertable=false, updateable=false) в getAnswer, потому что Hibernate не позволяет двум изменяемым свойствам использовать один и тот же столбец (userId также использует USER_ID), в противном случае я получу USER_ID в свойстве ответа, которое должно быть сопоставлено с помощью Insertable = false, updateable = false

Теперь взгляните на сопоставление getAnswer.

@ManyToOne
JoinColumns({
    JoinColumn(name="USER_ID", referencedColumnName="USER_ID", insertable=false, updateable=false),
    JoinColumn(name="ANSWER_INDEX", referencedColumnName="INFO_INDEX", insertable=false)
})

Потому что Hibernate жалуется, что нельзя смешивать разные вставляемые и обновляемые файлы.

Что мне нужно сделать, чтобы пройти его?

Будьте осторожны, это УСТАРЕВШАЯ система.

с уважением,

Это было полезно?

Решение 2

Согласно вопросу в сопоставлении getAnswer

@ManyToOne
JoinColumns({
    JoinColumn(name="USER_ID", referencedColumnName="USER_ID", insertable=false, updateable=false),
    JoinColumn(name="ANSWER_INDEX", referencedColumnName="INFO_INDEX", insertable=false)
})

Hibernate будет жаловаться, потому что он не позволяет смешивать различные вставляемые и обновляемые файлы.Обратите внимание на возможность вставки и обновления в USER_ID JoinColumn и возможность вставки только в ANSWER_INDEX JoinColumn.

Итак, чтобы передать его, я настроил ANSWER_INDEX JoinCollumn в соответствии с

JoinColumn(name="ANSWER_INDEX", referencedColumnName="INFO_INDEX", insertable=false, updateable=false)

Таким образом, Hibernate не будет жаловаться.

И я создал новое свойство под названием AnswerIndex.

private Integer answerIndex;   

@Column(name="ANSWER_INDEX", insertable=false)
public void getAnswerIndex() {
    return this.answerIndex;
}

Затем в User addAnswer

public void addAnswer(InfoRepository repository, Integer questionIndex, Info answer) {
    Info question = repository.getInfoById(new InfoId(getId(), questionIndex));

    if(question.getInfoCategory().equals(InfoCategory.ANSWER))
        throw new RuntimeException("Is not a question");

    if(question.getAnswer() != null)
        throw new RuntimeException("You can not post a new answer");

    answer.setInfoCategory(InfoCategory.ANSWER);
    answer.setInfoId(new InfoId(getId(), getInfoList().size()));

    getInfoList().add(answer);

    // Added in order to set up AnswerIndex property
    question.setAnswerIndex(answer.getInfoId().getIndex());
}

Другие советы

Ты бы кардинально упростите сопоставление, отказавшись от встроенного идентификатора и вместо этого используя суррогатный PK.

Если вам нужно использовать InfoId.index с какой-то целью (заказать вопросы/ответы?вы можете указать это в list сопоставление), сохраните его как обычное свойство.

UserId будет заменен на ManyToOne на User;другой конец ассоциации (в User class) будет отображаться как @OneToMany(mappedBy="User")

Почему ответ отображается как ManyToOne?Разве это не должно быть OneToMany (например.1 вопрос на множество ответов)?В любом случае, сопоставление класса с самим собой не идеально - вы по сути реализуете иерархию модели «списка смежности», которая неэффективна;плюс в вашем случае вам нужно будет убедиться, что это не более 2 уровней.я бы нарисовал карту Question и Answer как отдельные классы;вы можете заставить их реализовать общий интерфейс или расширить один и тот же базовый (возможно, абстрактный) класс;в любом случае вы сможете пользоваться неявным полиморфизмом, предоставляемым Hibernate.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top