使用没有 em.flush() 的 JPA 持久化深度对象图
Posted
技术标签:
【中文标题】使用没有 em.flush() 的 JPA 持久化深度对象图【英文标题】:Persisting deep object graph with JPA without em.flush() 【发布时间】:2011-04-12 16:27:12 【问题描述】:我有以下型号:
报告, ReportSection 和 ReportSectionProperty.
Report 有零到多个 ReportSections,ReportSection 有零到多个 ReportSectionPropert-ies。这将有资格作为三层深度对象图。
我创建新的报告,然后向其中添加一些部分,然后向其中添加一些属性。当我尝试保留 Report 时,我收到以下错误:
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]
所以,OpenJPA 是持久化对象图,但不知何故它是从中间开始的。 id_node 186 确实是 Report 表的下一个 id,但是很明显,在保存 ReportSection 时该对象没有保存。
如果我在添加部分或属性的每个操作之间放置 em.persist(report) 然后 em.flush(),一切正常。这是要走的路吗?
如果我不向部分添加任何属性,即使没有 em.flush(),持久报告也可以工作。
我使用 OpenJPA 2.0.3 作为 JPA 提供者。
也许是代码的一些相关部分:
报告.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
公共类 ReportSection @ManyToOne @JoinColumn(name="id_node") 私人报告报告; @OneToMany(targetEntity=ReportSectionProperty.class, cascade=CascadeType.ALL, mappedBy="reportSection") 私有列表报告SectionProperties; 公共无效集报告(报告报告) this.report = 报告; 公共无效 addReportSectionProperty(ReportSectionProperty reportSectionProperty) 同步(这个) if (getReportSectionProperties() == null) reportSectionProperties = new ArrayList(); reportSectionProperties.add(reportSectionProperty); reportSectionProperty.setReportSection(this);
ReportSectionProperty
公共类 ReportSectionProperty @ManyToOne(级联=CascadeType.ALL) @JoinColumn(name="id_report_section") 私人报告部分报告部分; 公共无效 setReportSection(ReportSection reportSection) this.reportSection = 报告部分;
【问题讨论】:
【参考方案1】:这可能是一个死线程,但由于我遇到了类似的问题,我想展示我是如何解决它的,以供将来参考(以防万一丢失的灵魂必须处理 OpenJPA)
尝试将此属性设置到您的 persistence.xml 中,以便 OpenJPA 可以以正确的顺序重新排列 sql 语句。
property name="openjpa.jdbc.SchemaFactory" value="native(ForeignKeys=true)"
http://openjpa.apache.org/faq.html#FAQ-CanOpenJPAreorderSQLstatementstosatisfydatabaseforeignkeyconstraints%253F
【讨论】:
嗯,可能就是这样!我周一去试试,谢谢! :)【参考方案2】:如果我在添加部分或属性的每个操作之间放置 em.persist(report) 然后 em.flush(),一切正常。这是要走的路吗?
如果定义了正确的级联设置并正确构建了双向关联(当然不包括任何 JPA 提供程序错误),则不需要这样做。第一部分看起来不错。但是我想看看你是怎么做最后一部分的。
【讨论】:
感谢您的回答。但是,当您说“最后一部分”时,我不确定您指的是什么。您是否在考虑“正确构建的双向关联”?我认为 @OneToMany(mappedBy=...) 和 @ManyToOne 注释涵盖了这一点。至少这是我在阅读文档时所理解的。您想要相关持久场景的完整代码示例吗? 也许值得注意的是,Report 本身是 Node 的一个特化,它是我模型中所有 Node 的基本抽象类。我使用 InheritanceType.JOINED 作为继承策略。 @Rocky "first part" 是指级联,"last part" 是指双向链接的设置。但是在第二次查看(在 addXxx 方法)之后,它看起来是正确的(虽然我想知道为什么你需要同步但这是另一个故事)。但是显示一些简单的代码来说明您如何设置图表和em.persist()
它不会受到伤害。【参考方案3】:
您是否尝试将 cascade=ALL 添加到从 ReportSection 到 Report 的 @ManyToOne 关系?
在父 Report 对象上发布您的 @Id 属性也可能会有所帮助。
【讨论】:
以上是关于使用没有 em.flush() 的 JPA 持久化深度对象图的主要内容,如果未能解决你的问题,请参考以下文章
我们如何让 JPA EntityManager Flush 工作
即使抛出错误,JPA EntityManager persist() 也会导致对象看起来分离
JPA 2.0 使用 Hibernate 作为提供者 - 例外:EntityManager 没有持久性提供者