假设这样的映射
@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提供的隐式多态性.