简体   繁体   English

使用JdbcSimpleCall从存储过程获取结构的pl / sql数组

[英]Getting pl/sql array of struct from stored procedure using JdbcSimpleCall

im trying to execute oracle stored procedure using SimpleJDBCCall, all tables and stored procedures are in restaurant schema, table looks like: 我试图使用SimpleJDBCCall执行oracle存储过程,所有表和存储过程都在餐厅模式中,表如下所示:

CREATE TABLE STAFF
(
    STAFF_ID             NUMBER(5),
    STAFF_FIRST_NAME     VARCHAR2(10 BYTE)        NOT NULL,
    STAFF_LAST_NAME      VARCHAR2(20 BYTE)        NOT NULL,
    STAFF_ROLE           VARCHAR2(20 BYTE)        NOT NULL,
    STAFF_OTHER_DETAILS  VARCHAR2(50 BYTE)
);

my type package: 我的类型包:

CREATE OR REPLACE PACKAGE Staff_Types 
AS
    TYPE Staff_Collection IS TABLE OF Staff%ROWTYPE;  
END Staff_Types;

my access package: 我的访问包:

CREATE OR REPLACE PACKAGE Staff_TAPI 
AS
    FUNCTION getAllStaff RETURN Staff_Types.Staff_Collection;
END Staff_TAPI;

CREATE OR REPLACE PACKAGE BODY Staff_Tapi
AS
    FUNCTION getAllStaff 
        RETURN Staff_Types.Staff_Collection
    IS
        all_staff Staff_Types.Staff_Collection;
    BEGIN
        SELECT * 
        BULK COLLECT INTO all_staff
        FROM Staff;

        RETURN all_staff;
    END;

END Staff_Tapi;

Java Access: Java访问:

@Component
@Qualifier("staffJdbcDAO")
public class StaffJDBCDAO implements StaffDAO {
    JdbcTemplate jdbcTemplate;
    SimpleJdbcCall getAllMembersSP;

    @Autowired
    @Qualifier("dataSource")
    DataSource dataSource;

    @Autowired
    @Qualifier("jdbcTemplate")
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
        initializeStoredProceduresCalls();
    }

    private void initializeStoredProceduresCalls() {
        getAllMembersSP = new SimpleJdbcCall(jdbcTemplate);
        getAllMembersSP.withCatalogName("Staff_Tapi");
        getAllMembersSP.withFunctionName("getAllStaff");
        getAllMembersSP.declareParameters(
            new SqlOutParameter("return",
                    Types.OTHER,
                    "Staff_Types.Staff_Collection",
                    new SqlReturnStructArray<>( new StaffMapper() )
            )
        );
        getAllMembersSP.compile();

    }

    @Override
    public List<Staff> getAllMembers() {
        Staff[] staff = getAllMembersSP.executeFunction(Staff[].class,new   HashMap<String,Object>() );
        return Arrays.asList(staff);
    }
}

mapping class: 映射类:

public class StaffMapper implements StructMapper<Staff> {

    @Override
    public STRUCT toStruct(Staff staff, Connection connection, String typeName) throws SQLException {
        StructDescriptor descriptor = StructDescriptor.createDescriptor(typeName, connection);

        Object[] attributes = new Object[5];
        attributes[0] = new Integer( staff.getId() );
        attributes[1] = new String("STAFF_FIRST_NAME");
        attributes[2] = new String("STAFF_LAST_NAME");
        attributes[3] = new String("STAFF_ROLE");
        attributes[4] = new String("STAFF_OTHER_DETAILS");
        Struct staffStruct = connection.createStruct(typeName,attributes);
        return new STRUCT(descriptor,connection,attributes);
    }

    @Override
    public Staff fromStruct(STRUCT struct) throws SQLException {
        StructDescriptor descriptor = struct.getDescriptor();
        ResultSetMetaData metaData = descriptor.getMetaData();
        Object[] attributes = struct.getAttributes();
        Map<String,Object> attributeMap = new HashMap<>();
        int idx = 1;
        for ( Object attribute : attributes )
            attributeMap.put( metaData.getColumnName(idx++),attribute );


        int id = ((Integer)attributeMap.get("STAFF_ID")).intValue();
        String firstName = (String) attributeMap.get("STAFF_FIRST_NAME");
        String lastName = (String) attributeMap.get("STAFF_LAST_NAME");
        String staffRole = (String) attributeMap.get("STAFF_ROLE");
        String otherDetails = (String) attributeMap.get("STAFF_OTHER_DETAILS");
        return new Staff(id,firstName,lastName,staffRole,otherDetails);
    }
}

and staff: 和员工:

public class Staff {
    private int id;
    private String firstName;
    private String lastName;
    private String profession;
    private String otherDetails;


    public Staff(int id, String firstName, String lastName, String profession, String otherDetails) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.profession = profession;
        this.otherDetails = otherDetails;
    }

    public int getId() {
        return id;
    }

    public int setId(int id) {
        this.id = id;
    }

    // and others getters and setters
}

when i execute getAllMembers from StaffDAO im constatly getting : CallableStatementCallback; 当我从StaffDAO执行getAllMembers时,即时获得:CallableStatementCallback; uncategorized SQLException for SQL [{? 未分类的SQLException for SQL [{? = call STAFF_TAPI.GETALLSTAFF()}]; =呼叫STAFF_TAPI.GETALLSTAFF()}]; SQL state [99999]; SQL状态[99999]; error code [17004]; 错误代码[17004]; Invalid column type: 1111; 无效的列类型:1111;

when i change return type parameter to Types.Array i get: CallableStatementCallback; 当我将返回类型参数更改为Types.Array时,我得到:CallableStatementCallback; uncategorized SQLException for SQL [{? 未分类的SQLException for SQL [{? = call STAFF_TAPI.GETALLSTAFF()}]; =呼叫STAFF_TAPI.GETALLSTAFF()}]; SQL state [99999]; SQL状态[99999]; error code [17074]; 错误代码[17074];
invalid name pattern: restaurant.Staff_Types.Staff_Collection; 无效的名称模式:restaurant.Staff_Types.Staff_Collection;

i tried in both ways with pattern "Staff_Types.Staf_collection" getting same results, im trying to do this for nearly 2 days without any idea what should i do, if anyone has any suggestions i will be greateful. 我以两种方式尝试了“ Staff_Types.Staf_collection”模式,得到了相同的结果,即时通讯试图将近2天不知道该怎么办,如果有人有任何建议,我将不胜感激。

In order to easily integrate your PL/SQL call, and since it is already built as a function: have you thought about something like this? 为了轻松集成您的PL / SQL调用,并且它已经作为函数构建,您是否考虑过类似的事情?

select * from TABLE(CAST(Staff_Tapi.getAllStaff() as Staff_Types.Staff_Collection))

This way, you can execute it easily as a regular JDBC query. 这样,您可以轻松地将其作为常规JDBC查询执行。 Once done, just process the ResultSet it returns with some minor variant of your fromStruct method in order to return a List<Staff> list to whatever business logic you have on top of it. 完成后,只需处理ResultSet并使用fromStruct方法的一些较小变体即可返回ResultSet ,以便将List<Staff>列表返回到其之上的任何业务逻辑。 Hope you find this useful! 希望你觉得这个有用!

You cannot load a PL/SQL record from a stored procedure through JDBC. 您不能通过JDBC从存储过程中加载PL / SQL record In fact, you cannot even load such a type from Oracle SQL. 实际上,您甚至无法从Oracle SQL加载此类。 See also this question for details: 另请参阅此问题以获取详细信息:

You can only load SQL types through JDBC (as opposed to PL/SQL types). 您只能通过JDBC加载SQL类型(与PL / SQL类型相反)。 Given your example, you'll need to write: 给定您的示例,您需要编写:

-- You cannot really avoid this redundancy
CREATE TYPE STAFF AS OBJECT
(
    STAFF_ID             NUMBER(5),
    STAFF_FIRST_NAME     VARCHAR2(10 BYTE)        NOT NULL,
    STAFF_LAST_NAME      VARCHAR2(20 BYTE)        NOT NULL,
    STAFF_ROLE           VARCHAR2(20 BYTE)        NOT NULL,
    STAFF_OTHER_DETAILS  VARCHAR2(50 BYTE)
);
CREATE TYPE STAFF_TABLE AS TABLE OF STAFF;

And then: 接着:

CREATE OR REPLACE PACKAGE Staff_TAPI 
AS
    FUNCTION getAllStaff RETURN STAFF_TABLE;
END Staff_TAPI;

You may want to capitalize your custom type in java code like 您可能需要在Java代码中使用大写的自定义类型,例如

    getAllMembersSP.declareParameters(
        new SqlOutParameter("return",
                Types.OTHER,
                "STAFF_TYPES.STAFF_COLLECTION",
                new SqlReturnStructArray<>( new StaffMapper() )
        )
    );

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

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