休眠将子表中自动生成的序列值插入子表

时间:2018-07-27 13:41:50

标签: java hibernate

想象一下,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分配给其所有外部参考并保存。但是,如果可能的话,我宁愿不做两步来保存一份工作。

enter image description here

模型类:

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

2 个答案:

答案 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();
        }
    }
}

此替代方法是一种手动方法,虽然不美观,但可以工作。仍然希望找到一种优雅的方法,它必须存在于某个地方,因为这是一个非常常见的用例。