Pergunta

Suponha que um mapeamento como este

@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);
    }

}

E uma pergunta e resposta mapeados por uma classe Informações

@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;
    }

}

Em getAnswer eu uso ManyToOne vez de OneToOne porque algumas questões relacionadas ao mapeamento OneToOne. Um OneToOne pode ser mapeada como um ManyToOne (original = verdadeiro em @JoinColumn). INFO_INDEX não está relacionado com qualquer finalidade específica. Apenas uma chave, a fim de suportes uma chave primária composta em um sistema legado.

Antes de responder, cuidar do seguinte:

Se um objeto tem um identificador atribuído, ou uma chave composta, o identificador deve ser atribuído à instância do objeto antes de chamar save ()

Então eu tenho para mapear JoinColumn (name = "USER_ID", referencedColumnName = "USER_ID", inserível = false, atualizável = false) em getAnswer porque o Hibernate não permite duas propriedades mutáveis ??compartilham o mesmo collumn (userId também usa USER_ID), caso contrário vou receber USER_ID na propriedade resposta deve ser mapeada com inserível = false, atualizável = false

Agora, dê uma olhada mapeamento getAnswer

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

Porque, Hibernate reclama que você não pode misturar diferentes inserível e atualizável

O que devo fazer para passá-lo?

Tome cuidado que é um sistema legado.

Atenciosamente,

Foi útil?

Solução 2

De acordo com a questão no mapeamento getAnswer

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

Hibernate vai reclamar porque não permite misturar diferentes inserível e atualizável. Observe um inserível e atualizável em USER_ID JoinColumn e só inserível em ANSWER_INDEX JoinColumn.

Assim, a fim de passá-lo, i configurar ANSWER_INDEX JoinCollumn accortding para

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

Desta forma, o Hibernate não vai reclamar.

E eu configurar uma nova propriedade chamada answerIndex

private Integer answerIndex;   

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

Então, em addAnswer usuário

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());
}

Outras dicas

Você faria drasticamente simplificar o seu mapeamento por renunciar id incorporado e utilizando um PK substituto em seu lugar.

Se você precisa usar InfoId.index para algum propósito (a ordem as perguntas / respostas? Você pode especificar que no mapeamento list), mantê-lo como uma propriedade regular.

UserId será substituído por ManyToOne em User; a outra extremidade da associação (na classe User) vai ser mapeada como @OneToMany(mappedBy="User")

Por que a resposta mapeada como ManyToOne? ele não deve ser OneToMany (por exemplo, 1 pergunta a muitas respostas)? De qualquer maneira, classe de mapeamento em si é inferior a ideal - você está implementando, basicamente, uma "lista de adjacência" hierarquia do modelo que é ineficiente; plus no seu caso, você vai precisar para se certificar de que não mais de 2 níveis é. Eu mapear Question e Answer como classes separadas; você pode tê-los implementar uma interface comum ou estender a mesma base (possivelmente abstrato) classe; de qualquer forma você vai ser capaz de desfrutar de polimorfismo implícito fornecido pelo Hibernate.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top