【问题标题】:A Stackoverflow mapping (Hibernate)Stackoverflow 映射(休眠)
【发布时间】:2010-11-27 08:39:21
【问题描述】:

假设一个像这样的映射

@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(@JoinColumn 中的 unique=true)。 INFO_INDEX 与任何特定目的无关。只需一个键即可支持 LEGACY 系统中的复合主键。

在回答之前,请注意以下事项:

如果一个对象有一个分配的标识符,或者一个复合键,在调用 save() 之前,标识符应该分配给对象实例

所以我必须在 getAnswer 中映射 JoinColumn(name="USER_ID", referencedColumnName="USER_ID", insertable=false, updateable=false) 因为 Hibernate 不允许两个可变属性共享相同collumn (userId 也使用 USER_ID) 否则我将在 answer 属性中获取 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 抱怨你不能混合不同的可插入和可更新

我应该怎么做才能通过它?

请注意它是一个遗留系统。

问候,

【问题讨论】:

    标签: java hibernate mapping orm


    【解决方案1】:

    您将大大通过放弃嵌入的 id 并改用代理 PK 来简化映射。

    如果您需要将InfoId.index 用于某些目的(订购问题/答案?您可以在list 映射中指定),请将其保留为常规属性。

    UserId 将在User 上替换为ManyToOne;另一个关联端(在User 类中)将映射为@OneToMany(mappedBy="User")

    为什么答案映射为ManyToOne?不应该是OneToMany(例如,1 个问题对多个答案)?无论哪种方式,将类映射到自身都不太理想-您基本上是在实现效率低下的“邻接列表”模型层次结构;另外,在您的情况下,您需要确保它不超过 2 个级别。我会将QuestionAnswer 映射为单独的类;您可以让它们实现一个通用接口或扩展相同的基类(可能是抽象类);无论哪种方式,您都可以享受 Hibernate 提供的隐式多态性。

    【讨论】:

    • 好Chss,其实就是ManyToOne。我使用它而不是 OneToOne 因为一些与 OneToOne 映射相关的问题。 OneToOne 可以映射为 ManyToOne(@JoinColumn 中的 unique=true)。 INFO_INDEX 与任何特定目的无关。只需一个键即可支持 LEGACY 系统中的复合主键。我明天试试。问候,
    【解决方案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;
    }
    

    然后在用户添加答案

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-11
      • 2014-12-27
      相关资源
      最近更新 更多