假设像这样的映射

@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 =&quot; USER_ID&quot;,referencedColumnName =&quot; USER_ID&quot;,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抱怨你不能混合不同的可插入和可更新的

我该怎么办才能通过它?

小心这是一个遗产系统。

的问候,

有帮助吗?

解决方案 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());
}

其他提示

您将彻底通过放弃嵌入式ID并使用代理PK来简化您的映射。

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

UserId 将被 User 上的 ManyToOne 取代;另一个关联结束(在 User 类中)将被映射为 @OneToMany(mappedBy =&quot; User&quot;)

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top