2009-09-11 7 views
3

Supposons une application comme celui-ciUne cartographie Stackoverflow (Hibernate)

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

} 

Et une question et réponse mis en correspondance par une classe Infos

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

} 

En RenvoieQuestion j'utilise ManyToOne au lieu de OneToOne parce que certaines questions lié à la cartographie OneToOne. Un OneToOne peut être mappé en tant que ManyToOne (unique = true dans @JoinColumn). INFO_INDEX n'est pas lié à un but spécifique. Juste une clé pour soutenir une clé primaire composée dans un système LEGACY.

Avant de répondre, prendre en charge les éléments suivants:

Si un objet a un identifiant attribué, ou une clé composite, l'identificateur doit être attribué à l'instance d'objet avant d'appeler save()

Donc je dois mapper JoinColumn (name = "USER_ID", referencedColumnName = "USER_ID", insérable = false, updateable = false) dans getAnswer car Hibernate ne permet pas à deux propriétés mutables de partager la même colonne (userId utilise également USER_ID) sinon j'obtiendra USER_ID en réponse pr opriété doit être mis en correspondance avec insérable = false, actualisable = false

Maintenant, jetez un oeil à la cartographie RenvoieQuestion

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

Parce que, Hibernate se plaint que vous ne pouvez pas mélanger différents insérables et actualisable

Que dois-je faire pour le passer?

Faites attention, c'est un système LEGACY.

salutations,

Répondre

1

Selon question dans la cartographie RenvoieQuestion

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

Hibernate se plaindra, car il ne permet mélanger différents insérables et actualisable. Remarquez un insertable et modifiable dans USER_ID JoinColumn et uniquement insérable dans ANSWER_INDEX JoinColumn.

Ainsi, afin de passer, je mis en place ANSWER_INDEX JoinCollumn accortding à

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

De cette façon, Hibernate ne se plaindra pas.

Et je mis en place une nouvelle propriété appelée answerIndex

private Integer answerIndex; 

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

Puis, dans l'utilisateur 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()); 
} 
2

Vous considérablement votre cartographie par simplifier id renoncer et en utilisant un intégré substitut PK à la place.

Si vous avez besoin d'utiliser InfoId.index dans un but précis (pour commander des questions/réponses? Vous pouvez spécifier cela dans le mappage list), conservez-le comme une propriété normale.

UserId sera remplacée par ManyToOne sur User; l'autre extrémité d'association (dans la classe User) sera mappée comme @OneToMany(mappedBy="User")

Pourquoi la réponse est-elle mappée comme ManyToOne? Ne devrait-il pas être OneToMany (par exemple, 1 question à plusieurs réponses)? Dans tous les cas, la mise en correspondance de la classe sur elle-même est loin d'être idéale - vous mettez en œuvre une hiérarchie de modèles de «liste d'adjacence» qui est inefficace; De plus, dans votre cas, vous devrez vous assurer qu'il n'y a pas plus de 2 niveaux. Je voudrais cartographier Question et Answer en tant que classes séparées; vous pouvez leur demander de mettre en place une interface commune ou d'étendre la même classe de base (éventuellement abstraite); de toute façon, vous serez en mesure de profiter du polymorphisme implicite fourni par Hibernate.

+0

Bonne CHSS, en fait ManyToOne. Je l'utilise à la place de OneToOne car certains problèmes liés au mapping OneToOne. Un OneToOne peut être mappé en tant que ManyToOne (unique = true dans @JoinColumn). INFO_INDEX n'est pas lié à un but spécifique. Juste une clé pour soutenir une clé primaire composée dans un système LEGACY. Je vais essayer demain. Cordialement, –

Questions connexes