2012-04-19 42 views
7

Tôi đang viết một quy trình để xử lý đối tượng được xác định bởi người dùng được lưu trữ trong ANYDATA. Kiểu đối tượng và tên thuộc tính chỉ có thể được biết trong thời gian chạy, vì vậy tôi không thể xác định viarable cho nó trong phần khai báo. Trong Java, tôi có thể sử dụng sự phản chiếu để đối phó với nó, tôi có thể biết tên lớp và tên trường. Sau đó, tôi có thể truy cập các lĩnh vực thông qua sự phản ánh. Có cách nào để làm điều đó trong PLSQL như thế không? Những gì trong đầu của tôi ngay bây giờ là tạo ra một chuỗi sql trong thủ tục động và thực hiện nó. Nhưng nó không phải là những gì tôi muốn chính xác.Phản ánh trong PLSQL?

Giả sử, người dùng A đã xác định loại ADT là create or replace type Person_type as object (fname varchar2(10), lname varchar2(10)); và tạo một đối tượng đối tượng và chèn nó vào ANYDATA.

Trong thủ tục của tôi, bằng cách nào đó tôi biết tôi cần phải đối phó với các thuộc tính đầu tiên của đối tượng này, đó là fname. Vì vậy, nếu biết loại quảng cáo ở vị trí đầu tiên, mã của tôi sẽ như sau:

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; 

Vì vậy, tôi nên làm gì để làm cho động? Cảm ơn trước.

+0

Nếu bạn biết rằng 'tempAnydata' là * thực sự * một' A.person_type' như bạn chắc chắn làm (nếu không bạn không thể làm được 'cái GetObject (adobject) 'với adobject chính xác kiểu này) sau đó bạn * cũng * biết thuộc tính đầu tiên của loại đó là gì. Hay tôi đang thiếu một cái gì đó? –

+0

A.person_type chỉ là một ví dụ, nó có thể là bất kỳ loại người dùng xác định. Nó có thể là B.anymal_type hoặc cái gì khác. – icespace

+1

Đánh máy tĩnh mạnh. (Smalltalker gắt gỏng già đi lang thang, lẩm bẩm tự :-) –

Trả lời

7

Bạn cần sử dụng ANYTYPE để mô tả ANYDATA và đảm bảo loại là chính xác. Sau đó, bạn có thể truy cập thuộc tính bằng cách sử dụng piecewisegetVarchar2.

Hầu hết mã bên dưới là để kiểm tra loại mà bạn không cần nếu bạn không lo lắng về an toàn loại.

Chức năng quay trở lại giá trị:

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; 
/

loại:

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); 

Test Run:

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; 
/

đầu ra :

Ford 
Paula 
+0

+1 - Tôi sẽ xóa câu trả lời của mình. Tôi vẫn nghĩ rằng kiến ​​trúc của OP là một công cụ đặc biệt, nhưng nếu chúng thực sự lumbered thì đây chính là giải pháp – APC

+0

@APC Tôi nghĩ bạn nên giữ câu trả lời của bạn, nó có thể hữu ích. Tôi đã nhìn thấy các giải pháp đối tượng quan hệ thường xuyên hơn ANYDATA. (Mặc dù nói chung tôi cố gắng để tránh cả hai người trong số họ; tôi luôn luôn là một chút hoài nghi của các giải pháp quá chung chung.) –

+0

Tuyệt vời! Cảm ơn bạn rất nhiều, jonearles. Đó thực sự là điều tôi muốn! ANYTYPE, rất vui được gặp bạn. – icespace