想象一下,Oracle数据库中有一个工作表,其主键是自动生成的序列。还有另一个表称为External_Reference。它们是一对多的关系,即一件作品可能有很多外部参考。
External_Reference具有一个外键Work_ID,用于表Work的主键ID。
使用Hibernate,想知道是否可以使用saveOrUpdate(object)保存作品saveOrUpdate(aWork)
,该作品将自动保存其所有外部引用吗?
Work work = new Work("Get started with Hibernate");
Set<ExternalReference> externalRefs = new HashSet<>();
ExternalReference ref1 = new ExternalReference("isbn", "23423454");
ref1.setWork(work); // work.getId() returns null before work being saved.
externalRefs.add(ref1);
ExternalReference ref2 = new ExternalReference("doi", "d2342-345553");
ref2.setWork(work);
externalRefs.add(ref2);
work.setExternalReferences(externalRefs);
// ORA-01400: cannot insert NULL into ("External_Reference"."WORK_ID")
aHibernateSession.saveOrUpdate(work);
挑战在于,在保存作品之前,您将无法知道自动生成的作品ID,这意味着您无法将其分配给作品的外部参考。
是的,您可以先保存工作而无需任何外部参考,以获取自动生成的工作ID,然后将工作ID分配给其所有外部参考并保存。但是,如果可能的话,我宁愿不做两步来保存一份工作。
模型类:
@Entity
@Table(name = "Work")
public class Work implements java.io.Serializable {
@Id
@Column(name = "ID", unique = true, nullable = false, precision = 22, scale = 0)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "WORK_SEQ")
@SequenceGenerator(name = "WORK_SEQ", sequenceName = "WORK_SEQ", allocationSize = 1, initialValue = 1)
public BigDecimal getId() {
return this.Id;
}
@OneToMany(fetch = FetchType.LAZY, mappedBy = "work", cascade = CascadeType.ALL, orphanRemoval=true)
public Set<ExternalReference> getExternalReferences() {
return this.externalReferences;
}
}
@Entity
@Table(name = "External_Reference")
public class ExternalReference implements java.io.Serializable {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "WORK_ID", nullable = false, insertable = false, updatable = false)
public Work getWork() {
return this.work;
}
}
答案 0 :(得分:0)
这里您只需要通过
ref1.setWorkId(work);
ref2.setWorkId(work);
另外,请检查休眠映射检查映射示例
//Work Class is Parent
@Entity
@Table(name = "Work")
public class Work {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "ID", unique = true, nullable = false)
private Long id;
@Column(name = "TITTLE", nullable = false)
private String title;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "work")
private Set<ExternalReference> externalReference;
public Work() {
}
public Work(String title) {
this.title = title;
}
//setter and getter
}
//ExternalReference Class is Child
@Entity
@Table(name = "External_Reference")
public class ExternalReference {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "ID", unique = true, nullable = false)
private Long id;
@Column(name = "Ref_Source", nullable = false)
private String ref_source;
@Column(name = "Ref_Id", nullable = false)
private String ref_id;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name ="Work_ID")
private Work work;
public ExternalReference() {
}
public ExternalReference(String ref_source, String ref_id) {
this.ref_source = ref_source;
this.ref_id = ref_id;
}
//setter and getter
}
答案 1 :(得分:0)
我想到并测试过的解决方法是一种手动方式(供您参考):
对于新作品,请首先从数据库中手动获取下一个序列,然后将其分配给该作品及其所有外部引用。然后,只需使用State
对于现有作品,只需使用其现有ID,然后将其分配给新的外部参考(如果有)。
从数据库中获取序列将保证序列是唯一的。这是线程安全的。
aHibernateSession.saveOrUpdate(work);
为使此替代方法起作用,您需要注释掉Work的密钥生成器,如下所示:
public BigDecimal getNextSeq() {
Session session = null;
try {
session = sessionFactory.openSession(); // sessionFactory should have been initialised.
Query query = session.createSQLQuery("select WORK_SEQ.nextval as num from dual")
.addScalar("num", StandardBasicTypes.BIG_DECIMAL);
BigDecimal nextSeq = (BigDecimal) query.uniqueResult();
return nextSeq;
} finally {
if (session != null){
session.close();
}
}
}
此替代方法是一种手动方法,虽然不美观,但可以工作。仍然希望找到一种优雅的方法,它必须存在于某个地方,因为这是一个非常常见的用例。