Java SQLData – 使用列表/数组转换为用户对象?
我正在学习如何使用SQLData并且在回送到我的对象时遇到问题。
我的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; );
我的Java看起来像这样:
public class Activities implements SQLData { private String sqlType = "ACTIVITIES_T"; List 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); } }
我在readSQL中尝试过一些东西但是我没有取得多大成功 – 我错过了什么?
我正在使用JDBC调用一个PLSQL存储过程,其OUT参数为“activities_t”:
Map map = connection.getTypeMap(); map.put("ACTIVITIES_T", Class.forName("Activities")); connection.setTypeMap(map); callableStatement = connection.prepareCall("{call GET_ACTIVITIES(?)}"); callableStatement.execute();
谢谢! 史蒂夫
(以上大部分都来自内存,因为代码在工作……)
您需要为ACTIVITY_T
类型添加类型映射,并为ACTIVITIES_T
添加类型映射。 你的问题不清楚你是否已经这样做了。
让我们假设你已经完成了这个并创建了一个名为Activity
的类,它也实现了SQLData
。 完成后,以下内容应足以阅读活动中的活动列表:
public void readSQL(SQLInput stream, String typeName) throws SQLException { Array array = stream.readArray(); this.list = new ArrayList(); for (Object obj : (Object[])array.getArray()) { list.add((Activity)obj); } }
提示:
- JDBC API在类型名称方面区分大小写; 如果您的类型名称不完全匹配,您将看到
Unable to resolve type
错误。 除非在其create语句中双引号,否则Oracle将大写您的类型名称。 - 如果类型不在默认架构中,则可能需要指定
SCHEMA.TYPE_NAME
。 - 如果您要连接的用户不是所有者,请记住在类型上
grant execute
。
如果您对包执行了而不是类型,则getArray()
在尝试查找类型元数据时会抛出exception。
的getArray()
我的解决方案与Luke的解决方案基本相同。 但是,我需要在获取数组时提供类型映射: array.getArray(typeMap)
您还可以在Connection上设置默认类型映射,但这对我不起作用。
调用getArray()
您将获得一个对象类型的数组,即您创建的表示activity_t
的SQLData
实现
这是一个您可能会觉得有用的通用函数:
public static List listFromArray(Array array, Class 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 list = new ArrayList<>(objectArray.length); for (Object o : objectArray) { list.add(typeClass.cast(o)); } return list; }
writeArray()
弄清楚如何编写数组是令人沮丧的,Oracle API需要一个Connection来创建一个Array,但是在writeSQL(SQLOutput sqlOutput)
的上下文中没有明显的Connection。 幸运的是, 这个博客有一个技巧/黑客来获取我在这里使用过的OracleConnection
。
使用createOracleArray()
创建数组时,请指定类型名称的列表类型 ,而不是对象类型。 即activity_list_t
这是编写数组的通用函数。 在您的情况下, listType
将是"activity_list_t"
,您将传入List
public static void writeArrayFromList(SQLOutput sqlOutput, String listType, @Nullable List 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); }
注意:有一点我认为setTypeMap
是必需的,但现在当我删除该行时,我的代码仍然有效,所以我不确定是否有必要。