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);
}
}
由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提供的隐式多态性。