在toplink中映射nested table

nested table是Oracle所特有的一种实现,作为被Oracle收购了的OR-Mapping工具Toplink,自然也应该对其提供支持。但是在寻找这个的过程中,又一次深深体会到了Toplink文档的稀少(OTN,也只有OTN)以及语焉不详(我就不信有人看着官方文档能调出来的)。为以后起见,这里记录一下吧。

 

假设有以下的nested table:

 

CREATE OR REPLACE TYPE STUDENT_TYPE AS OBJECT
(
  STUDENT_ID   NUMBER(4),
  STUDENT_NAME VARCHAR2(10)
);

CREATE OR REPLACE TYPE STUDENT_LIST IS TABLE OF STUDENT_TYPE;

CREATE TABLE SCHOOL(SCHOOL_ID NUMBER(2) primary key, SCHOOL_NAME VARCHAR2(14),
 STUDENTS STUDENT_LIST) NESTED TABLE STUDENTS store AS STUDENTS_TAB;


ALTER TABLE STUDENTS_TAB add CONSTRAINT UK_STUDENTS_TAB UNIQUE(STUDENT_ID);

 

和以下的JO

public class School {
    private int id;

    private String name;

    private List<Student> students;

    //skip  getter, setter
}

 

public class Student {
    private int id;
    private String name;

    // skip getter,setter
    
    
    
}

 

那么相应的Descriptor应该这么写

 

 

 public ClassDescriptor buildSchoolDescriptor() {

        ObjectRelationalDescriptor descriptor = new ObjectRelationalDescriptor();
        descriptor.setJavaClass(School.class);
        descriptor.addTableName("SCHOOL");
        descriptor.addPrimaryKeyFieldName("SCHOOL.SCHOOL_ID");

        DirectToFieldMapping idMapping = new DirectToFieldMapping();
        idMapping.setAttributeName("id");
        idMapping.setFieldName("SCHOOL_ID");
        descriptor.addMapping(idMapping);

        DirectToFieldMapping nameMapping = new DirectToFieldMapping();
        nameMapping.setAttributeName("name");
        nameMapping.setFieldName("SCHOOL.SCHOOL_NAME");
        descriptor.addMapping(nameMapping);

        ObjectArrayMapping studentsMapping = new ObjectArrayMapping();
        studentsMapping.setReferenceClass(Student.class);
        studentsMapping.setAttributeName("students");
        studentsMapping.setFieldName("STUDENTS");
        studentsMapping.setStructureName("STUDENT_LIST");
        descriptor.addMapping(studentsMapping);

        return descriptor;

    }

 

 public ClassDescriptor buildStudentDescriptor() {

        ObjectRelationalDescriptor descriptor = new ObjectRelationalDescriptor();
        descriptor.setJavaClass(Student.class);
        descriptor.descriptorIsAggregate();
        descriptor.setStructureName("STUDENT_TYPE");
        descriptor.addPrimaryKeyFieldName("id");
        descriptor.addFieldOrdering("id");
        descriptor.addFieldOrdering("name");

        descriptor.addDirectMapping("id", "id");
        descriptor.addDirectMapping("name", "name");

        return descriptor;

    }

 

相应的测试代码如下

 Server server = project.createServerSession();
        server.login();
        UnitOfWork uow = server.acquireUnitOfWork();
        ClientSession cs = server.acquireClientSession();

        server.shouldLogMessages();
        uow.shouldLogMessages();
        uow.setLogLevel(1);

        School school = new School();
        school.setId(1);
        school=(School)uow.readObject(school);
        System.out.println(school.getStudents().get(0).getId());
        school.getStudents().get(0).setName("NN");
        uow.commit();

 

 

在这个问题上我花了一整天时间,主要是在官方文档这里 完全没有把和核心讲出来。

1,正如论坛 jsuther 所言,

 

In TopLink if the nested table is of refs, then you use the NestedTableMapping (target class is not aggregate), if it is a nested table or varray of object types, then you use the ObjectArrayMapping (target class is aggregate).

也就是说,所谓的NestedTableMapping,居然只对ref nested table有效,普通的nested table应该用ObjectArrayMapping, 这是何等跳跃的思维啊!

 

2 在Student Descriptor中,一定要有以下两句,不然会报ora-17049 "Inconsistent java and sql object types"

descriptor.addFieldOrdering("id");
descriptor.addFieldOrdering("name");

 

3.还是在Student Descriptor中,添加DirectMapping时一定要写成以下方式,

 descriptor.addDirectMapping("id", "id");
 descriptor.addDirectMapping("name", "name");

    切忌写成以下这样

descriptor.addDirectMapping("id", "STUDENT_ID");

   这里我没有去看源码,既然addDirectMapping添加的是一个哑元(不要求指定数据库Column name) 又要求指定fieldOrdering,估计在组装对象时是按顺序来的,也就是把STUDENT_TYPE中出现的属性依照addFieldOrdering依次塞给Student上的属性。为了验证这个猜想,把addFieldOrdering的顺序颠倒一下变成

descriptor.addFieldOrdering("name");
descriptor.addFieldOrdering("id");

 

果然报了java.lang.NumberFormatException: For input string: "NN",验证了我的猜想

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值