如何在数据库存储递归对象?同类型对象引用存储报错解决
解决JDO存储递归对象时的参数未设置问题
你遇到的Parameter "#2" is not set错误,本质是JDO在持久化子Unit(比如unit2)时,无法正确获取父Unit(unit1)的主键值来填充PARENT_UNIT_ID字段。下面是具体的诊断和解决方案:
问题根源分析
- 字段访问权限配置缺失:你的
Unit类字段都是private,但JDO默认可能需要通过getter/setter访问字段,或者你需要显式配置让JDO直接访问字段。 - 主键策略未明确指定:你手动给
id赋值,但JDO默认可能认为主键是自动生成的,导致无法识别你设置的id值。 - 递归关联类型未明确:
parentUnit是递归的多对一关联,需要在JDO配置中明确关联类型,否则JDO无法正确处理引用关系。 - 代码拼写错误:你代码里的
PersistanceManager是拼写错误,正确应为PersistenceManager,这会导致编译或运行时问题。
解决方案步骤
1. 修正JDO映射配置(package.jdo)
更新配置,添加字段访问策略、主键策略,并明确关联类型:
<?xml version="1.0" encoding="UTF-8" ?> <jdo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/jdo/jdo" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/jdo/jdo http://xmlns.jcp.org/xml/ns/jdo/jdo_3_1.xsd" version="3.1"> <package name="pmo.domain.entities"> <!-- 添加access="field"让JDO直接访问私有字段 --> <class name="Unit" table="unit" access="field"> <field name="id" primary-key="true"> <column name="id"/> <!-- 明确主键由应用程序分配 --> <value-strategy value="application"/> </field> <!-- 显式配置name字段 --> <field name="name"> <column name="name"/> </field> <field name="parentUnit" type="many-to-one"> <column name="parent_unit_id" target-field="id"/> <foreign-key name="unit_id_fk" /> <!-- 允许父单元为null(根节点) --> <null-value default="true"/> </field> </class> </package> </jdo>
2. 修正代码中的拼写错误和持久化逻辑
修正PersistenceManager的拼写,并确保父Unit在持久化子Unit前已经被JDO管理(可以添加flush同步到数据库):
package pmo.domain.entities; import javax.jdo.JDOHelper; import javax.jdo.PersistenceManager; import javax.jdo.PersistenceManagerFactory; import javax.jdo.Transaction; public class ExampleTest { public static void main(String[] args) { // 注意main是小写 Unit unit1 = new Unit(0, "Unit 1"); Unit unit2 = new Unit(1, "Unit 2", unit1); Unit unit3 = new Unit(2, "Unit 3", unit2); PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("Test"); PersistenceManager pm = pmf.getPersistenceManager(); // 修正拼写错误 Transaction transaction = pm.currentTransaction(); try { transaction.begin(); // 先持久化根节点 pm.makePersistent(unit1); // 强制同步到数据库,确保unit1的id被JDO识别 pm.flush(); pm.makePersistent(unit2); pm.flush(); pm.makePersistent(unit3); transaction.commit(); System.out.println("所有Unit已成功持久化!"); } finally { if (transaction.isActive()) { transaction.rollback(); } pm.close(); pmf.close(); // 记得关闭PersistenceManagerFactory } } }
3. 验证Unit类的构造函数
确保Unit类的字段都能被正确初始化,你的构造函数是没问题的,但可以添加getter/setter(如果后续需要),不过JDO配置了access="field"后不需要也可以。
为什么这些修改能解决问题?
access="field"让JDO直接访问私有字段,避免因缺少getter/setter导致的字段无法读取问题。value-strategy="application"告诉JDO主键由应用程序提供,它会直接使用你设置的id值,而不是尝试自动生成。type="many-to-one"明确了parentUnit是多对一的递归关联,JDO会正确处理父对象的引用,将其id填充到外键字段中。pm.flush()强制将对象同步到数据库,确保父对象的主键在持久化子对象前已经被确认,避免JDO无法解析引用的问题。
内容的提问来源于stack exchange,提问作者Facon
相关产品推荐
相关产品推荐

