JPA:如何在更新祖父实体时更新孙子实体?
JPA: How to update grandchild entities when updating grandfather entity?
我创建了表格来存储来自解析非常嵌套的 xml 文件的信息。因此我数据库中的表也是嵌套的。顶级实体称为 SpecimenTb。
@Entity
@Table(name="SPECIMEN_TB")
public class SpecimenTb implements Serializable {
private String mrn;
@Column(name="SPECIMEN_NO", unique = true)
private String specimenNo;
@OneToMany(mappedBy="specimenTb", cascade=CascadeType.ALL)
private List<FmReportTb> fmReportTbs;
}
SpecimenTb 有一个名为 FmReportTb 的 child 实体,它与 FmReportGeneTb
有自己的一对多关系
@Entity
@Table(name="FM_REPORT_TB")
public class FmReportTb implements Serializable {
//bi-directional many-to-one association to SpecimenTb
@ManyToOne
@JoinColumn(name="SPECIMEN_ID")
private SpecimenTb specimenTb;
@OneToMany(mappedBy="fmReportTb", cascade=CascadeType.ALL)
private List<FmReportGeneTb> fmReportGeneTbs;
}
以后可能会有更新版本的文件,所以我需要在我的代码中实现更新方案。当我坚持时,我通过 specimenNo. 在 SpecimenTb 中查找记录。如果不存在,则插入新记录。否则,更新相同的记录,父亲,children 和 grandkids.
SpecimenDao specimenDao = new SpecimenDao(em);
SpecimenTb specimenTb = specimenDao.findSpecimenBySpecno(blockId);
FmReportTb report = null;
if (specimenTb != null) { // update
report = specimenTb.getFmReportTbs().get(0);
} else { // insert
report = new FmReportTb();
}
if (report.getFmReportGeneTbs() != null) { // update
geneList = report.getFmReportGeneTbs();
geneList.clear();
} else { //insert
geneList = new ArrayList<FmReportGeneTb>();
}
// parse "Genes" section of xml and store in geneList
for (Node gene : genes) {
FmReportGeneTb geneTb = new FmReportGeneTb();
<< set a bunch of stuff for geneTb>>
geneTb.setFmReportTb(report);
}
geneList.add(geneTb);
report.setFmReportGeneTb(geneList);
if (specimenTb == null) { // insert new record
specimenTb = new SpecimenTb();
specimenTb.setSpecimenNo(blockId);
specimenTb.setMrn(mrn);
report.setSpecimenTb(specimenTb);
reports.add(report);
specimenTb.setFmReportTbs(reports);
specimenDao.persistSpecimen(specimenTb);
} else { // update
report.setSpecimenTb(specimenTb);
reports.add(report);
specimenDao.updateSpecimen(specimenTb, mrn, reports);
}
在DAOclass中,持久化和更新方法如下:
// 插入
public void persistSpecimen(SpecimenTb specimen) {
EntityTransaction transaction = entityManager.getTransaction();
try {
transaction.begin();
entityManager.persist(specimen);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
}
}
//更新
public void updateSpecimen(SpecimenTb specimen, String mrn, List<FmReportTb> reports) {
EntityTransaction transaction = entityManager.getTransaction();
try {
transaction.begin();
specimen.setSpecimenNo(blockId);
specimen.setMrn(mrn);
specimen.setFmReportTbs(reports);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
}
}
Insert 完全符合我的要求,由于 cascade=CascadeType.ALL
,它保留了父实体和下面的所有实体。当我更新时,它确实更新了 SpecimenTb 和 FmReportTb 中的旧记录,但倾向于在 FmReportGeneTb 中插入一系列新记录。所以我最终在 FmReportGeneTb 中附加了一组新记录,这些记录链接到同一个 FmReportTb 而不是更新(新旧版本中的 GeneList 的长度可能不同)。 FmReportGeneTb 实际上有 child 个实体和 grandchild 个实体我没有展示。如何自上而下更新所有相关表?
我不知道你在 FmReportTb
上设置了哪些其他字段,但是看到你的代码,在第一行有一个
FmReportTb report = new FmReportTb();
这就解释了为什么你的样本中有两个 FmReportTb
的记录。
如果你想更新现有的 FmReportTb
你应该在更新之前设置它的 id。
我创建了表格来存储来自解析非常嵌套的 xml 文件的信息。因此我数据库中的表也是嵌套的。顶级实体称为 SpecimenTb。
@Entity
@Table(name="SPECIMEN_TB")
public class SpecimenTb implements Serializable {
private String mrn;
@Column(name="SPECIMEN_NO", unique = true)
private String specimenNo;
@OneToMany(mappedBy="specimenTb", cascade=CascadeType.ALL)
private List<FmReportTb> fmReportTbs;
}
SpecimenTb 有一个名为 FmReportTb 的 child 实体,它与 FmReportGeneTb
有自己的一对多关系@Entity
@Table(name="FM_REPORT_TB")
public class FmReportTb implements Serializable {
//bi-directional many-to-one association to SpecimenTb
@ManyToOne
@JoinColumn(name="SPECIMEN_ID")
private SpecimenTb specimenTb;
@OneToMany(mappedBy="fmReportTb", cascade=CascadeType.ALL)
private List<FmReportGeneTb> fmReportGeneTbs;
}
以后可能会有更新版本的文件,所以我需要在我的代码中实现更新方案。当我坚持时,我通过 specimenNo. 在 SpecimenTb 中查找记录。如果不存在,则插入新记录。否则,更新相同的记录,父亲,children 和 grandkids.
SpecimenDao specimenDao = new SpecimenDao(em);
SpecimenTb specimenTb = specimenDao.findSpecimenBySpecno(blockId);
FmReportTb report = null;
if (specimenTb != null) { // update
report = specimenTb.getFmReportTbs().get(0);
} else { // insert
report = new FmReportTb();
}
if (report.getFmReportGeneTbs() != null) { // update
geneList = report.getFmReportGeneTbs();
geneList.clear();
} else { //insert
geneList = new ArrayList<FmReportGeneTb>();
}
// parse "Genes" section of xml and store in geneList
for (Node gene : genes) {
FmReportGeneTb geneTb = new FmReportGeneTb();
<< set a bunch of stuff for geneTb>>
geneTb.setFmReportTb(report);
}
geneList.add(geneTb);
report.setFmReportGeneTb(geneList);
if (specimenTb == null) { // insert new record
specimenTb = new SpecimenTb();
specimenTb.setSpecimenNo(blockId);
specimenTb.setMrn(mrn);
report.setSpecimenTb(specimenTb);
reports.add(report);
specimenTb.setFmReportTbs(reports);
specimenDao.persistSpecimen(specimenTb);
} else { // update
report.setSpecimenTb(specimenTb);
reports.add(report);
specimenDao.updateSpecimen(specimenTb, mrn, reports);
}
在DAOclass中,持久化和更新方法如下: // 插入
public void persistSpecimen(SpecimenTb specimen) {
EntityTransaction transaction = entityManager.getTransaction();
try {
transaction.begin();
entityManager.persist(specimen);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
}
}
//更新
public void updateSpecimen(SpecimenTb specimen, String mrn, List<FmReportTb> reports) {
EntityTransaction transaction = entityManager.getTransaction();
try {
transaction.begin();
specimen.setSpecimenNo(blockId);
specimen.setMrn(mrn);
specimen.setFmReportTbs(reports);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
}
}
Insert 完全符合我的要求,由于 cascade=CascadeType.ALL
,它保留了父实体和下面的所有实体。当我更新时,它确实更新了 SpecimenTb 和 FmReportTb 中的旧记录,但倾向于在 FmReportGeneTb 中插入一系列新记录。所以我最终在 FmReportGeneTb 中附加了一组新记录,这些记录链接到同一个 FmReportTb 而不是更新(新旧版本中的 GeneList 的长度可能不同)。 FmReportGeneTb 实际上有 child 个实体和 grandchild 个实体我没有展示。如何自上而下更新所有相关表?
我不知道你在 FmReportTb
上设置了哪些其他字段,但是看到你的代码,在第一行有一个
FmReportTb report = new FmReportTb();
这就解释了为什么你的样本中有两个 FmReportTb
的记录。
如果你想更新现有的 FmReportTb
你应该在更新之前设置它的 id。