3

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

3 Answers 3

1

This might be a dead thread, but since i faced a similar issue i would like to show how i managed to resolved it, for future references (in case of any lost soul have to deal with OpenJPA)

Try to set this property into your persistence.xml so OpenJPA can rearrange the sql statement in the correct order.

property name="openjpa.jdbc.SchemaFactory" value="native(ForeignKeys=true)"

http://openjpa.apache.org/faq.html#FAQ-CanOpenJPAreorderSQLstatementstosatisfydatabaseforeignkeyconstraints%253F

Sign up to request clarification or add additional context in comments.

1 Comment

Hm, that might just be it! I'll try it out on Monday, thanks! :)
0

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.

3 Comments

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?
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 "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.
0

Did you try adding cascade=ALL to the @ManyToOne relationship from ReportSection to Report?

It might help to post your @Id property on the parent Report object as well.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.