Oracle PLSQL中的反射?
我正在编写一个过程来处理存储在ANYDATA中的用户定义对象。对象类型和属性名只能在运行时知道,因此我无法在declare部分为其定义变量。在Java中,我可以使用反射来处理它,我可以知道类名和字段名。然后我可以通过反射来访问字段。在PLSQL中有这样做的方法吗?我现在脑子里想的是在过程中动态地创建一个sql字符串并执行它。但这并不是我想要的 比方说,用户A将ADT类型定义为Oracle PLSQL中的反射?,oracle,plsql,user-defined-types,Oracle,Plsql,User Defined Types,我正在编写一个过程来处理存储在ANYDATA中的用户定义对象。对象类型和属性名只能在运行时知道,因此我无法在declare部分为其定义变量。在Java中,我可以使用反射来处理它,我可以知道类名和字段名。然后我可以通过反射来访问字段。在PLSQL中有这样做的方法吗?我现在脑子里想的是在过程中动态地创建一个sql字符串并执行它。但这并不是我想要的 比方说,用户A将ADT类型定义为创建或替换类型Person\u type作为对象(fname varchar2(10),lname varchar2(10
创建或替换类型Person\u type作为对象(fname varchar2(10),lname varchar2(10))
并创建一个对象实例,并将其插入到ANYDATA中
在我的过程中,不知何故我知道我需要处理这个对象的第一个属性,即fname。因此,如果首先知道adt类型,我的代码如下:
declare
adobject A.Person_type; -- HERE! I don't know the type yet, so I can't define adobject!
tempAnydata anydata;
rt number;
vbuffer varchar2(10);
...
begin
select somecolumn
into tempAnydata
from sometable
where something='something' for update;
rt := tempAnydata.GetObject(adobject);
vbuffer := adobject.fname; -- HERE! I don't know the attribute name is fname!
-- deal with vbuffer here
end;
那么,我应该做些什么来动态地创建它呢?提前感谢。您需要使用
ANYTYPE
来描述ANYDATA
并确保类型正确。然后可以使用分段
和getVarchar2
访问该属性
下面的大部分代码用于检查类型,如果您不关心类型安全,则不需要检查类型
返回值的函数:
create or replace function get_first_attribute(
p_anydata in out anydata --note the "out" - this is required for the "piecewise"
) return varchar2 is
v_typecode pls_integer;
v_anytype anytype;
begin
--Get the typecode, and the ANYTYPE
v_typecode := p_anydata.getType(v_anytype);
--Check that it's really an object
if v_typecode = dbms_types.typecode_object then
--If it is an object, find the first item
declare
v_first_attribute_typecode pls_integer;
v_aname varchar2(32767);
v_result pls_integer;
v_varchar varchar2(32767);
--Variables we don't really care about, but need for function output
v_prec pls_integer;
v_scale pls_integer;
v_len pls_integer;
v_csid pls_integer;
v_csfrm pls_integer;
v_attr_elt_type anytype;
begin
v_first_attribute_typecode := v_anytype.getAttrElemInfo(
pos => 1, --First attribute
prec => v_prec,
scale => v_scale,
len => v_len,
csid => v_csid,
csfrm => v_csfrm,
attr_elt_type => v_attr_elt_type,
aname => v_aname);
--Check typecode of attribute
if v_first_attribute_typecode = dbms_types.typecode_varchar2 then
--Now that we've verified the type, get the actual value.
p_anydata.piecewise;
v_result := p_anydata.getVarchar2(c => v_varchar);
--DEBUG: Print the attribute name, in case you're curious
--dbms_output.put_line('v_aname: '||v_aname);
return v_varchar;
else
raise_application_error(-20000, 'Unexpected 1st Attribute Typecode: '||
v_first_attribute_typecode);
end if;
end;
else
raise_application_error(-20000, 'Unexpected Typecode: '||v_typecode);
end if;
end;
/
create or replace type Person_type as object (fname varchar2(10), lname varchar2(10));
create or replace type other_type as object (first_name varchar2(10), poetry clob);
declare
--Create records
v_type1 person_type := person_type('Ford', 'Prefect');
v_type2 other_type := other_type('Paula', 'blah blah...');
v_anydata anydata;
begin
--Convert to ANYDATA.
--Works as long as ANYDATA is an object with a varchar2 as the first attribute.
v_anydata := anydata.convertObject(v_type1);
dbms_output.put_line(get_first_attribute(v_anydata));
v_anydata := anydata.convertObject(v_type2);
dbms_output.put_line(get_first_attribute(v_anydata));
end;
/
类型:
create or replace function get_first_attribute(
p_anydata in out anydata --note the "out" - this is required for the "piecewise"
) return varchar2 is
v_typecode pls_integer;
v_anytype anytype;
begin
--Get the typecode, and the ANYTYPE
v_typecode := p_anydata.getType(v_anytype);
--Check that it's really an object
if v_typecode = dbms_types.typecode_object then
--If it is an object, find the first item
declare
v_first_attribute_typecode pls_integer;
v_aname varchar2(32767);
v_result pls_integer;
v_varchar varchar2(32767);
--Variables we don't really care about, but need for function output
v_prec pls_integer;
v_scale pls_integer;
v_len pls_integer;
v_csid pls_integer;
v_csfrm pls_integer;
v_attr_elt_type anytype;
begin
v_first_attribute_typecode := v_anytype.getAttrElemInfo(
pos => 1, --First attribute
prec => v_prec,
scale => v_scale,
len => v_len,
csid => v_csid,
csfrm => v_csfrm,
attr_elt_type => v_attr_elt_type,
aname => v_aname);
--Check typecode of attribute
if v_first_attribute_typecode = dbms_types.typecode_varchar2 then
--Now that we've verified the type, get the actual value.
p_anydata.piecewise;
v_result := p_anydata.getVarchar2(c => v_varchar);
--DEBUG: Print the attribute name, in case you're curious
--dbms_output.put_line('v_aname: '||v_aname);
return v_varchar;
else
raise_application_error(-20000, 'Unexpected 1st Attribute Typecode: '||
v_first_attribute_typecode);
end if;
end;
else
raise_application_error(-20000, 'Unexpected Typecode: '||v_typecode);
end if;
end;
/
create or replace type Person_type as object (fname varchar2(10), lname varchar2(10));
create or replace type other_type as object (first_name varchar2(10), poetry clob);
declare
--Create records
v_type1 person_type := person_type('Ford', 'Prefect');
v_type2 other_type := other_type('Paula', 'blah blah...');
v_anydata anydata;
begin
--Convert to ANYDATA.
--Works as long as ANYDATA is an object with a varchar2 as the first attribute.
v_anydata := anydata.convertObject(v_type1);
dbms_output.put_line(get_first_attribute(v_anydata));
v_anydata := anydata.convertObject(v_type2);
dbms_output.put_line(get_first_attribute(v_anydata));
end;
/
测试运行:
create or replace function get_first_attribute(
p_anydata in out anydata --note the "out" - this is required for the "piecewise"
) return varchar2 is
v_typecode pls_integer;
v_anytype anytype;
begin
--Get the typecode, and the ANYTYPE
v_typecode := p_anydata.getType(v_anytype);
--Check that it's really an object
if v_typecode = dbms_types.typecode_object then
--If it is an object, find the first item
declare
v_first_attribute_typecode pls_integer;
v_aname varchar2(32767);
v_result pls_integer;
v_varchar varchar2(32767);
--Variables we don't really care about, but need for function output
v_prec pls_integer;
v_scale pls_integer;
v_len pls_integer;
v_csid pls_integer;
v_csfrm pls_integer;
v_attr_elt_type anytype;
begin
v_first_attribute_typecode := v_anytype.getAttrElemInfo(
pos => 1, --First attribute
prec => v_prec,
scale => v_scale,
len => v_len,
csid => v_csid,
csfrm => v_csfrm,
attr_elt_type => v_attr_elt_type,
aname => v_aname);
--Check typecode of attribute
if v_first_attribute_typecode = dbms_types.typecode_varchar2 then
--Now that we've verified the type, get the actual value.
p_anydata.piecewise;
v_result := p_anydata.getVarchar2(c => v_varchar);
--DEBUG: Print the attribute name, in case you're curious
--dbms_output.put_line('v_aname: '||v_aname);
return v_varchar;
else
raise_application_error(-20000, 'Unexpected 1st Attribute Typecode: '||
v_first_attribute_typecode);
end if;
end;
else
raise_application_error(-20000, 'Unexpected Typecode: '||v_typecode);
end if;
end;
/
create or replace type Person_type as object (fname varchar2(10), lname varchar2(10));
create or replace type other_type as object (first_name varchar2(10), poetry clob);
declare
--Create records
v_type1 person_type := person_type('Ford', 'Prefect');
v_type2 other_type := other_type('Paula', 'blah blah...');
v_anydata anydata;
begin
--Convert to ANYDATA.
--Works as long as ANYDATA is an object with a varchar2 as the first attribute.
v_anydata := anydata.convertObject(v_type1);
dbms_output.put_line(get_first_attribute(v_anydata));
v_anydata := anydata.convertObject(v_type2);
dbms_output.put_line(get_first_attribute(v_anydata));
end;
/
产出:
Ford
Paula
如果您知道
tempAnydata
确实是一个A.person\u类型
,就像您肯定知道的那样(否则,您无法使用正是这种类型的adobject执行GetObject(adobject)
),那么您也知道该类型的第一个属性是什么。或者我遗漏了什么?A.person\u类型只是一个例子,它可以是任何用户定义的类型。可能是B.anymal_类型或其他类型。静态强类型很糟糕。(脾气暴躁的小人走掉了,自言自语道:——)+1-我要删除我的答案。我仍然认为OP的架构很奇特,但如果他们真的笨重,这是正确的solution@APC我认为你应该保留你的答案,它可能会有帮助。我见过的对象关系解决方案比任何数据都多。(虽然总的来说,我尽量避免使用这两种方法;我对过于通用的解决方案总是有点怀疑。)太棒了!非常感谢你,jonearles。这才是我真正想要的!ANYTYPE,很高兴认识你。它的核心部分(这是我来这里寻找的东西)原来是anydata.convertobject(self.gettypename()
(或者如果你在外面查看,用类型实例的名称替换self
,例如OP示例中的adobject
)。