简体   繁体   中英

JPA: How to update grandchild entities when updating grandfather entity?

I've created tables to store information from parsing xml files that are very nested. Therefore the tables in my database are nested too. The top level entity is called 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 has a child entity called FmReportTb which has its own onetomany relationship to 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;
}

It is possible a newer version of file will come at a later time, so I need to implement update scheme in my code. When I persist, I look for record in SpecimenTb by specimenNo. If it does not exist, insert new record. Otherwise, update the same records, father, children and 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);
    }

In the DAO class, persist and update methods are as follows: // insert

public void persistSpecimen(SpecimenTb specimen) {
    EntityTransaction transaction = entityManager.getTransaction();
    try {
        transaction.begin();
        entityManager.persist(specimen);
        transaction.commit();
    } catch (Exception e) {
        transaction.rollback();
    }
}

// update

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 works exactly what I wanted, it persists father entity and all entities underneath thanks to cascade=CascadeType.ALL . When I update though, it does update the old record in SpecimenTb and FmReportTb but tends to insert a new series of records in FmReportGeneTb. So I ended up appending a new set of records in FmReportGeneTb that is linked to the same FmReportTb instead of updating (GeneList in old and new versions may differ in length). There are actually child entities and grandchild entities of FmReportGeneTb that I did not show. How do I update all related tables from top down?

I don't know what other fields do you set on FmReportTb , but seen your code, on the first line there is a

FmReportTb report = new FmReportTb();

That explain why you ended having two records of FmReportTb in your specimen. If you want to update the existing FmReportTb you should set its id before update it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM