Domanda

Supponi una mappatura come questa

@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 una domanda e risposta mappata da una classe 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;
    }

}

In getAnswer uso ManyToOne invece di OneToOne perché alcuni problemi relativi alla mappatura di OneToOne. Un OneToOne può essere mappato come ManyToOne (unique = true in @JoinColumn). INFO_INDEX non è collegato a nessuno scopo specifico. Solo una chiave per supportare una chiave primaria composta in un sistema LEGACY.

Prima di rispondere, prenditi cura di quanto segue:

  

Se un oggetto ha un identificatore assegnato, o una chiave composita, l'identificatore DOVREBBE ESSERE ASSEGNATO all'istanza dell'oggetto PRIMA di chiamare save ()

Quindi devo mappare JoinColumn (name = " USER_ID " ;, referencedColumnName = " USER_ID " ;, insertable = false, aggiornabile = false) in getAnswer perché Hibernate non consente la condivisione di due proprietà mutabili la stessa colonna (userId utilizza anche USER_ID) altrimenti otterrò USER_ID nella proprietà di risposta deve essere mappato con insertable = false, updateable = false

Ora dai un'occhiata alla mappatura di getAnswer

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

Perché, Hibernate si lamenta che non puoi mescolare diversi inseribili e aggiornabili

Cosa devo fare per passarlo?

Fai attenzione, è un sistema LEGACY.

saluti,

È stato utile?

Soluzione 2

Secondo la domanda nella mappatura getAnswer

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

Hibernate si lamenterà perché non consente di mescolare diversi inseribili e aggiornabili. Notare un inseribile e aggiornabile in USER_ID JoinColumn e inseribile solo in ANSWER_INDEX JoinColumn.

Quindi, al fine di passarlo, ho impostato ANSWER_INDEX JoinCollumn accortding su

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

In questo modo, Hibernate non si lamenterà.

E ho impostato una nuova proprietà chiamata answerIndex

private Integer answerIndex;   

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

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

Altri suggerimenti

Dovresti drasticamente semplificare la tua mappatura rinunciando all'ID incorporato e usando invece un PK surrogato.

Se hai bisogno di usare InfoId.index per qualche scopo (per ordinare domande / risposte? puoi specificarlo nella mappatura list ), tenerlo come una normale proprietà .

UserId sarà sostituito da ManyToOne su User ; l'altra estremità dell'associazione (nella classe User ) sarà mappata come @OneToMany(mappedBy="User")

Perché la risposta è mappata come ManyToOne ? Non dovrebbe essere OneToMany (ad es. 1 domanda a molte risposte)? In entrambi i casi, mappare la classe su se stesso è tutt'altro che ideale: in pratica stai implementando un "elenco di adiacenza" gerarchia di modelli inefficiente; inoltre nel tuo caso dovrai assicurarti che non superi i 2 livelli. Mapperei Question e Answer come classi separate; puoi farli implementare un'interfaccia comune o estendere la stessa classe base (possibilmente astratta); in entrambi i casi potrai godere del polimorfismo implicito fornito da Hibernate.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top