简体   繁体   English

Java SQLData-使用列表/数组强制转换为用户对象?

[英]Java SQLData - Cast to user object with a list/array?

I'm learning on how to use SQLData and having an issue with casting back to my object. 我正在学习如何使用SQLData,并且在投射回我的对象​​时遇到问题。

My Oracle Types looks something like this: 我的Oracle类型看起来像这样:

CREATE OR REPLACE TYPE activities_t AS OBJECT
(
   list   activity_list_t;
);

CREATE OR REPLACE TYPE activity_list_t AS TABLE OF activity_t;

CREATE OR REPLACE TYPE activity_t AS OBJECT
(
   startDate  DATE;
   endDate    DATE;
);

And my Java looks like this: 我的Java看起来像这样:

public class Activities implements SQLData {
    private String sqlType = "ACTIVITIES_T";
    List<Activity> list;

    // must have default ctor!
    public Activities() {
    }

    public String getSQLTypeName() throws SQLException
    { 
        return sqlType; 
    }

    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }

    public void readSQL(SQLInput stream, String typeName) throws SQLException 
    {
        Array a = stream.readArray();
        // :(
    }

    public void writeSQL(SQLOutput stream) throws SQLException 
    {
        // stream.writeArray(this.list);
    }
}

I've tried a few things in readSQL but I am not having much success - what am I missing? 我已经在readSQL中尝试了几件事,但没有取得太大的成功-我缺少什么?

I am calling a PLSQL stored procedure which has an OUT parameter of "activities_t" using JDBC: 我正在使用JDBC调用一个OUT参数为“ activities_t”的PLSQL存储过程:

Map map = connection.getTypeMap();
map.put("ACTIVITIES_T", Class.forName("Activities"));
connection.setTypeMap(map);

callableStatement = connection.prepareCall("{call GET_ACTIVITIES(?)}");
callableStatement.execute();

Thanks! 谢谢! Steve 史蒂夫

(most of the above is from memory as the code is at work...) (以上大部分内容都来自内存,因为代码正在起作用...)

You'll need to add a type mapping for the type ACTIVITY_T as well as the one for ACTIVITIES_T . 您需要为ACTIVITY_TACTIVITIES_T类型添加一个类型映射。 It's not clear from your question whether you've already done this. 从您的问题尚不清楚您是否已经完成此操作。

Let's assume you've done this and created a class called Activity which implements SQLData as well. 假设您已完成此操作,并创建了一个名为Activity的类,该类也实现了SQLData Once you've done that, the following should suffice to read the activity list within Activities : 一旦你这样做了,下面应该足以阅读中的活动列表Activities

    public void readSQL(SQLInput stream, String typeName) throws SQLException {
        Array array = stream.readArray();
        this.list = new ArrayList<Activity>();
        for (Object obj : (Object[])array.getArray()) {
            list.add((Activity)obj);
        }
    }

Tips: 提示:

  • JDBC APIs are case-sensitive with regard to type names; JDBC API在类型名称方面区分大小写。 you will see a Unable to resolve type error if your type name does not exactly match. 如果您的类型名称不完全匹配,则会看到“ Unable to resolve type错误。 Oracle will uppercase your type name unless you double-quoted the name in its create statement. Oracle将大写您的类型名称,除非您在其create语句中用双引号将该名称引起来。
  • You may need to specify SCHEMA.TYPE_NAME if the type isn't in your default schema. 如果类型不在默认模式中,则可能需要指定SCHEMA.TYPE_NAME
  • Remember to grant execute on types if the user you are connecting with is not the owner. 如果要连接的用户不是所有者,请记住要grant execute对类型的grant execute
    If you have execute on the package, but not the type, getArray() will throw an exception when it tries to look for type metadata. 如果您在程序包上执行过,但没有执行过类型,则getArray()在尝试查找类型元数据时将引发异常。

getArray() getArray()

My solution is essentially the same as Luke's. 我的解决方案与Luke的解决方案基本相同。 However, I needed to provide a type mapping when getting the array: array.getArray(typeMap) You can also set a default type map on the Connection, but this didn't work for me. 但是,我需要在获取数组时提供类型映射: array.getArray(typeMap)您还可以在Connection上设置默认的类型映射,但这对我不起作用。

When calling getArray() you get an array of the object type, ie the SQLData implementation you created that represents activity_t 调用getArray()将获得对象类型的数组,即创建的代表activity_tSQLData实现。

Here is a generic function you might find useful: 这是一个通用函数,您可能会发现它有用:

public static <T> List<T> listFromArray(Array array, Class<T> typeClass) throws SQLException {
    if (array == null) {
        return Collections.emptyList();
    }
    // Java does not allow casting Object[] to T[]
    final Object[] objectArray = (Object[]) array.getArray(getTypeMap());
    List<T> list = new ArrayList<>(objectArray.length);
    for (Object o : objectArray) {
        list.add(typeClass.cast(o));
    }
    return list;
}

writeArray() writeArray()

Figuring out how to write an array was frustrating, Oracle APIs require a Connection to create an Array, but you don't have an obvious Connection in the context of writeSQL(SQLOutput sqlOutput) . 弄清楚如何编写数组令人沮丧,Oracle API需要使用Connection才能创建数组,但是在writeSQL(SQLOutput sqlOutput)上下文中没有明显的Connection。 Fortunately, this blog has a trick/hack to get the OracleConnection , which I've used here. 幸运的是, 此博客有一个技巧/技巧来获取OracleConnection ,我在这里使用了它。

When you create an array with createOracleArray() you specify the list type for the type name, NOT the object type. 当使用createOracleArray()创建数组时,请为类型名称而不是对象类型指定列表类型。 ie activity_list_t activity_list_t

Here's a generic function for writing arrays. 这是用于编写数组的通用函数。 In your case, listType would be "activity_list_t" and you would pass in a List<Activity> 在您的情况下, listType将为"activity_list_t"并且您将传递List<Activity>

public static <T> void writeArrayFromList(SQLOutput sqlOutput, String listType, @Nullable List<T> list) throws SQLException {
    final OracleSQLOutput out = (OracleSQLOutput) sqlOutput;
    OracleConnection conn = (OracleConnection) out.getSTRUCT().getJavaSqlConnection();
    conn.setTypeMap(getTypeMap());  // not needed?
    if (list == null) {
        list = Collections.emptyList();
    }
    final Array array = conn.createOracleArray(listType, list.toArray());
    out.writeArray(array);
}

Note: at one point I thought setTypeMap was required, but now when I remove that line my code still works, so I'm not sure if it's necessary. 注意:曾经我以为setTypeMap是必需的,但是现在当我删除该行时,我的代码仍然有效,所以我不确定是否有必要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM