You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在数据库存储递归对象?同类型对象引用存储报错解决

解决JDO存储递归对象时的参数未设置问题

你遇到的Parameter "#2" is not set错误,本质是JDO在持久化子Unit(比如unit2)时,无法正确获取父Unit(unit1)的主键值来填充PARENT_UNIT_ID字段。下面是具体的诊断和解决方案:

问题根源分析

  1. 字段访问权限配置缺失:你的Unit类字段都是private,但JDO默认可能需要通过getter/setter访问字段,或者你需要显式配置让JDO直接访问字段。
  2. 主键策略未明确指定:你手动给id赋值,但JDO默认可能认为主键是自动生成的,导致无法识别你设置的id值。
  3. 递归关联类型未明确:parentUnit是递归的多对一关联,需要在JDO配置中明确关联类型,否则JDO无法正确处理引用关系。
  4. 代码拼写错误:你代码里的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:26:15