如何调用 Oracle PL/SQL 对象超级方法

Posted

技术标签:

【中文标题】如何调用 Oracle PL/SQL 对象超级方法【英文标题】:How to call an Oracle PL/SQL object super method 【发布时间】:2012-02-20 14:45:42 【问题描述】:

我想调用一个被覆盖的 PL/SQL 方法。这是一个例子:

-- super class
create or replace type test as object
(
  n number,
  member procedure proc(SELF in out nocopy test, s varchar2)
)
alter type test not final
/

create or replace type body test is
  member procedure proc(SELF in out nocopy test, s varchar2) is
  begin
    dbms_output.put_line('test1: n='||nvl(self.n, 'null')||' s='||s);
    self.n := to_number(s);
  end;
end;
/

-- derived class
create or replace type test2 under test
(
  overriding member procedure proc(SELF in out nocopy test2, s varchar2)
)
/

现在我想调用proc 方法的继承版本。当我尝试进行像 treat(self as test).proc(s); 这样的显式转换时,由于 PLS-00363: expression 'SYS_TREAT' cannot be used as an assignment target

,它不会编译

当我使用局部变量时类型体编译:

create or replace type body test2 is
  overriding member procedure proc(SELF in out nocopy test2, s varchar2) is 
    O test;
  begin
    O := treat(self as test);
    O.proc(s);
  end;
end;
/

但是当我像这样运行我的示例时

declare
  obj test2;
begin
  obj := test2(0);
  obj.proc('1');
end;

...它抛出 ORA-21780: 超出对象持续时间的最大数量。

有什么方法可以调用 test::proc(不进行序列化/反序列化)?

并且...在调用proc之后,任何更改的属性(即n)如何反映在obj中?


更新(谢谢,tbone):

我使用模板方法(“之前”和“之后”)更改了方法的组织。每当我需要扩展方法时,我都会添加它们。

create or replace type test as object
(
  n number,
  member procedure proc      (SELF in out nocopy test, s varchar2),
  member procedure afterProc (SELF in out nocopy test, s varchar2)
  member procedure beforeProc(SELF in out nocopy test, s varchar2),
)
not final
/

create or replace type body test is
  member procedure proc(SELF in out nocopy test, s varchar2) is
  begin
    beforeProc(s);
    dbms_output.put_line('test1: n='||nvl(n, 'null')||' s='||s);
    n := to_number(s);
    afterProc(s);
  end;
  member procedure afterProc (SELF in out nocopy test, s varchar2) is begin null; end;
  member procedure beforeProc(SELF in out nocopy test, s varchar2) is begin null; end;
end;
/

【问题讨论】:

来自文档看起来像 TREAT 用于访问子类型方法/属性,而不是超级。我可能错了,但请参阅docs.oracle.com/cd/E11882_01/appdev.112/e11822/adobjbas.htm 是的,你是对的。文档说 TREAT 只能访问子类型。但是我应该如何使用超类呢? 【参考方案1】:

要访问超级方法,请尝试通用调用或通用表达式。例如,使用人员超类型和学生子类型:

CREATE OR REPLACE TYPE person_typ AS OBJECT (
    idno number,
    name varchar2(30),
    phone varchar2(20),
    MAP MEMBER FUNCTION get_idno RETURN NUMBER,
    MEMBER FUNCTION show RETURN VARCHAR2)
NOT FINAL;

CREATE OR REPLACE TYPE BODY person_typ AS
  MAP MEMBER FUNCTION get_idno RETURN NUMBER IS
  BEGIN
    RETURN idno;
  END;
  MEMBER FUNCTION show RETURN VARCHAR2 IS
  BEGIN
    -- function that can be overriden by subtypes MEMBER FUNCTION show RETURN VARCHAR2 IS BEGIN
    RETURN 'Id: ' || TO_CHAR(idno) || ', Name: ' || name;
  END;
END;

CREATE TYPE student_typ UNDER person_typ (
    dept_id NUMBER,
    major VARCHAR2(30),
    OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2)
NOT FINAL;

CREATE TYPE BODY student_typ AS
  OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2 IS
  BEGIN
    RETURN (self AS person_typ).show || ' -- Major: ' || major ;
  END;
END;

-- Using Generalized Invocation
DECLARE
myvar student_typ := student_typ(100, 'Sam', '6505556666', 100, 'Math');
name VARCHAR2(100); 
BEGIN
name := (myvar AS person_typ).show; --Generalized invocation 
END;

-- Using Generalized Expression
DECLARE
myvar2 student_typ := student_typ(101, 'Sam', '6505556666', 100, 'Math');
name2 VARCHAR2(100); 
BEGIN
name2 := person_typ.show((myvar2 AS person_typ)); -- Generalized expression 
END;

编辑:

如果您使用的是 10g,则需要组织函数有点不同,但子函数的功能相同以调用超级方法:

CREATE TYPE BODY person_typ AS 
  MAP MEMBER FUNCTION get_idno RETURN NUMBER IS 
  BEGIN
    RETURN idno; 
  END;
  -- static function that can be called by subtypes 
  STATIC FUNCTION show_super (person_obj in person_typ) RETURN VARCHAR2 IS
  BEGIN 
    RETURN 'Id: ' || TO_CHAR(person_obj.idno) || ', Name: ' || person_obj.name;
  END;
  -- function that can be overriden by subtypes 
  MEMBER FUNCTION show RETURN VARCHAR2 IS 
  BEGIN
    RETURN person_typ.show_super ( SELF ); 
  END;
END;

CREATE TYPE student_typ UNDER person_typ ( 
  dept_id NUMBER,
  major VARCHAR2(30), 
  OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2) 
  NOT FINAL;

CREATE TYPE BODY student_typ AS 
  OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2 IS 
  BEGIN
    RETURN person_typ.show_super ( SELF ) || ' -- Major: ' || major ;
  END;
END;

现在你可以从 student 调用 show_super() 来调用 person 方法,或者只调用 show() 来调用 student 方法。

来自文档,希望对您有所帮助。

【讨论】:

谢谢,很好的答案。然而,“AS”是在 11g 中引入的。我想这意味着 10g 没有办法。

以上是关于如何调用 Oracle PL/SQL 对象超级方法的主要内容,如果未能解决你的问题,请参考以下文章

PL/SQL对象成员函数——java方法

使用带有布尔输入参数的 PL/SQL 在 oracle 中调用 java 存储过程

oracle SQL语句中怎么样调用存储过程

带有 PL SQL 表类型参数的 Oracle 存储过程的 JDBC 调用

从 0jdbc6 JDBCthin 驱动程序调用具有自定义对象返回类型的 Oracle PL/SQL 过程

Oracle PL/SQL:如何从 VARRAY 的 REF 中进行 DEREF?