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):
- 创建对象表:用于持久化对象实例,
REF类型需要指向数据库中存储的对象
CREATE TABLE example_obj_table OF example_type;
- 修改集合类型为REF集合
CREATE OR REPLACE TYPE example_ref_table_type AS TABLE OF REF example_type; /
- 使用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
相关产品推荐
相关产品推荐

