views:

52

answers:

1

I have following model:

Report, ReportSection and ReportSectionProperty.

Report has zero to many ReportSections, ReportSection has zero to many ReportSectionPropert-ies. This would qualifie as three levels deep object graph.

I create new Report, then add some sections to it, then add some properties to it. When I try to persist Report, I get following error:

Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: ERROR: insert or update on table "report_section" violates foreign key constraint "fk_report_section_report"
  Detail: Key (id_node)=(186) is not present in table "report". {prepstmnt 20859482 INSERT INTO core.report_section (index_section, name, report_section_type, id_node) VALUES (?, ?, ?, ?) [params=?, ?, ?, ?]} [code=0, state=23503]

So, OpenJPA is persisting object graph, but somehow it started from the middle. id_node 186 is indeed the next id of the Report table but, obviously that object is not saved when ReportSection is being saved.

If I put em.persist(report) then em.flush() between each operation of adding sections or properties, everything works. Is this the way to go?

If I don't add any properties to sections, persisting Report works, even without em.flush().

I use OpenJPA 2.0.3 as JPA provider.


Maybe some relevant parts of the code:

Report.java

public class Report{

    @OneToMany(targetEntity = ReportSection.class, cascade = CascadeType.ALL, mappedBy="report")
    private List reportSections;

    public void addReportSection(ReportSection section){
        synchronized (this) {
            if (getReportSections() == null)
                reportSections = new ArrayList();
            reportSections.add(section);
            section.setReport(this);
        }
    }
}

ReportSection.java

public class ReportSection{

    @ManyToOne
    @JoinColumn(name="id_node")
    private Report report;

    @OneToMany(targetEntity=ReportSectionProperty.class, cascade=CascadeType.ALL,   mappedBy="reportSection")
    private List reportSectionProperties;

    public void setReport(Report report) {
        this.report = report;
    }

    public void addReportSectionProperty(ReportSectionProperty reportSectionProperty){
        synchronized (this) {
            if (getReportSectionProperties() == null)
                reportSectionProperties = new ArrayList();
            reportSectionProperties.add(reportSectionProperty);
            reportSectionProperty.setReportSection(this);
        }
    }
}

ReportSectionProperty

public class ReportSectionProperty{

    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="id_report_section")
    private ReportSection reportSection;

    public void setReportSection(ReportSection reportSection) {
        this.reportSection = reportSection;
    }
}
A: 

If I put em.persist(report) then em.flush() between each operation of adding sections or properties, everything works. Is this the way to go?

This shouldn't be necessary with proper cascading settings defined and with bidirectional associations properly constructed (excluding any JPA provider bug of course). The first part looks OK. But I'd like to see how you do the last part.

Pascal Thivent
Thank you for your answer. But, I'm not sure to what are you reffering to when you say "last part". Are you thinking of "bidirectional associations properly constructed"? I think that that is covered by @OneToMany(mappedBy=...) and @ManyToOne annotations. At least that is what I have understood reading the documentation. Do you want entire code sample of the persisting scenario in question?
Rocky
Maybe it is worth of noting that Report itself is a specialization of Node which is base abstract class for all Nodes in my model. I am using InheritanceType.JOINED as inheritance strategy.
Rocky
@Rocky *"first part"* was referring to the cascading, *"last part"* was referring to the setup of the bidirectional link. But after a second look (at the addXxx methods), its looks correct (although I'm wondering why you need the synchronized but this is another story). But showing some simple code illustrating how you setup the graph and `em.persist()` it wouldn't hurt.
Pascal Thivent