You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PL/SQL中如何按引用传递对象实例?为何集合中对象修改不影响原对象

Oracle对象类型在集合中为何是值传递而非引用传递?

你创建的自定义对象类型和表类型代码如下:

自定义对象类型

-- A dummy type with one attribute      
CREATE OR REPLACE TYPE example_type AS OBJECT
(
  value VARCHAR2(50),
  CONSTRUCTOR FUNCTION example_type (value_in VARCHAR2) RETURN SELF AS RESULT
);
/

CREATE OR REPLACE TYPE BODY example_type AS
  CONSTRUCTOR FUNCTION example_type (value_in VARCHAR2) RETURN SELF AS RESULT IS
  BEGIN
    SELF.value := value_in;
    RETURN;
  END;
END;
/

对象表类型

-- A table of example_type
CREATE OR REPLACE TYPE example_table_type AS TABLE OF example_type;
/

测试PL/SQL代码

declare   
  Item example_type;
  ItemsList example_table_type;
          
  Value1 varchar2(15);
  Value2 varchar2(15);
begin
  Item := example_type(value_in => 'a');
          
  ItemsList := example_table_type();
  ItemsList.extend(1);
  ItemsList(ItemsList.count) := Item;
          
  ItemsList(1).value := 'b';    -- Replace the object value with 'b'
          
  Value1 := Item.value;         -- This returns 'a'. Why hasn't this value changed?
  Value2 := ItemsList(1).value; -- This returns 'b'
end;
/

问题原因

这并非你的代码出错,而是Oracle对象模型和C#的核心差异:

  • Oracle对象类型默认是值类型:当你把Item赋值给集合元素时,Oracle会创建一个原对象的完整副本存入集合,而非存储指向原对象的引用。后续修改集合中的对象,只会影响这个副本,原对象的属性值不会同步变化。
  • C#类默认是引用类型:赋值操作传递的是对象的内存引用,集合中存储的是引用,所以修改集合中的对象会直接影响原对象实例。

实现引用传递效果的方法

如果需要在Oracle中实现类似C#的引用传递行为,需要使用REF类型结合对象表(OBJECT TABLE):

  1. 创建对象表:用于持久化对象实例,REF类型需要指向数据库中存储的对象
CREATE TABLE example_obj_table OF example_type;
  1. 修改集合类型为REF集合
CREATE OR REPLACE TYPE example_ref_table_type AS TABLE OF REF example_type;
/
  1. 使用REF类型的PL/SQL示例
declare   
  Item example_type;
  ItemsList example_ref_table_type;
  ref_item REF example_type;
  
  Value1 varchar2(15);
  Value2 varchar2(15);
begin
  Item := example_type(value_in => 'a');
  -- 将对象存入对象表并获取引用
  INSERT INTO example_obj_table VALUES(Item) RETURNING REF(Item) INTO ref_item;
  
  ItemsList := example_ref_table_type();
  ItemsList.extend(1);
  ItemsList(ItemsList.count) := ref_item;
  
  -- 通过引用修改对象属性
  UPDATE example_obj_table t SET t.value = 'b' WHERE REF(t) = ItemsList(1);
  
  -- 刷新原对象的属性值
  SELECT VALUE(t) INTO Item FROM example_obj_table t WHERE REF(t) = ref_item;
  
  Value1 := Item.value;         -- 现在返回'b'
  Value2 := DEREF(ItemsList(1)).value; -- 返回'b'
end;
/

注意:REF类型依赖数据库持久化,所有对象操作都会涉及到数据库表的读写,这和C#中内存对象的引用传递在性能和使用方式上有明显区别。


内容的提问来源于stack exchange,提问作者Thomas Carlton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 12:25:14