java-*映射(休眠)

假设这样的映射

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

}

以及由信息类映射的问题和答案

@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系统中支持复合主键.

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

If an object has an assigned identifier, or a composite key, the identifier SHOULD BE ASSIGNED to the object instance BEFORE calling save()

所以我必须在getAnswer中映射JoinColumn(name =“ USER_ID”,referencedColumnName =“ USER_ID”,insertable = false,updateable = false),因为Hibernate不允许两个可变属性共享同一列(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抱怨您不能混合使用不同的可插入和可更新

我该怎么做才能通过?

请注意,这是一个LEGACY系统.

问候,

解决方法:

通过放弃嵌入的id并使用替代PK,可以大大简化映射.

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

UserId将被User上的ManyToOne取代;另一个关联端(在User类中)将映射为@OneToMany(mappedBy =“ User”)

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

上一篇:python SQLAlchemy的Mapping与Declarative详解


下一篇:带有代码优先的EF 4.1中的TPH继承映射问题