*** 映射(休眠)
Posted
技术标签:
【中文标题】*** 映射(休眠)【英文标题】:A *** mapping (Hibernate) 【发布时间】: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 抱怨你不能混合不同的可插入和可更新
我应该怎么做才能通过它?
请注意它是一个遗留系统。
问候,
【问题讨论】:
【参考方案1】:您将大大通过放弃嵌入的 id 并改用代理 PK 来简化映射。
如果您需要将InfoId.index
用于某些目的(订购问题/答案?您可以在list
映射中指定),请将其保留为常规属性。
UserId
将在User
上替换为ManyToOne
;另一个关联端(在User
类中)将映射为@OneToMany(mappedBy="User")
为什么答案映射为ManyToOne
?不应该是OneToMany
(例如,1 个问题对多个答案)?无论哪种方式,将类映射到自身都不太理想-您基本上是在实现效率低下的“邻接列表”模型层次结构;另外,在您的情况下,您需要确保它不超过 2 个级别。我会将Question
和Answer
映射为单独的类;您可以让它们实现一个通用接口或扩展相同的基类(可能是抽象类);无论哪种方式,您都可以享受 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());
【讨论】:
以上是关于*** 映射(休眠)的主要内容,如果未能解决你的问题,请参考以下文章