PL/SQL:有什么技巧可以避免对象的克隆吗?

2023-12-24

如果我们将一个对象变量分配给 pl/sql 中的其他对象变量,则该对象将被克隆,因为 pl/sql 不支持引用。例如,以下代码将打印两个不同的句子:

create or replace type cla as object    -- class (would be very complex)
(
  name  varchar2(50)
);

declare
    o1 cla;
    o2 cla;
begin
    o1 := cla('hi cloning world');
    o2 := o1;
    o1.name = 'goodbye cloning world';

    dbms_output.put_line('o1.name: ' || o1.name);
    dbms_output.put_line('o2.name: ' || o2.name);
end;

所以我想我可以将对象封装到其他对象(外部对象)中,如果我将外部对象分配给其他外部对象,那么内部对象就不会被克隆:

create or replace type cla as object    -- class (would be very complex)
(
  name  varchar2(10)
);

create or replace type eo_c as object   -- class to encapsulate objects
(
  o  cla                                -- encapsulation is easy
);

declare
    eo eo_c;
    eo2 eo_c;
begin
    eo := eo_c( cla('n1') );            -- eo is easy to create
    dbms_output.put_line('eo.name: ' || eo.o.name); -- real object is easy to access

    eo2 := eo;      -- eo_c object is cloned, cla object shouldn't be cloned
    eo.o.name := 'n2';      -- if eo.o == eo2.o then we are changing both names
    dbms_output.put_line('eo.name: '  || eo.o.name);
    dbms_output.put_line('eo2 name: ' || eo2.o.name);
end;

但这会再次打印两个不同的句子,因此内部对象也被克隆。

我可以将对象封装到其他类型的变量中以避免内部对象的克隆吗?或者更一般地说,是否有一些技巧可以避免对象的克隆,同时允许一种简单的方法来使用它?


根据 Alex 的建议(使用关联数组),我创建了一个封装对象的包,因此我们可以以抽象的方式使用它们,就像它们是引用一样:

create or replace type cla as object        -- complex class
(
    name varchar2(10)
);


create or replace package eo as     -- package to encapsulate objects
    type ao_t                       -- type for hash (associative array)
        is table of cla
        index by varchar2(100);
    o ao_t;                         -- hash of objects
end;


declare
    o1 varchar2(100);
    o2 varchar2(100);
begin
    o1 := 'o1';                         -- objects are hash indexes now
    eo.o(o1) := new cla('hi');          -- store new object into the hash
    o2 := o1;                           -- assign object == assign index
    eo.o(o1).name := 'bye';             -- change object attribute

    dbms_output.put_line('eo.o(o1).name: ' || eo.o(o1).name);
    dbms_output.put_line('eo.o(o2).name: ' || eo.o(o2).name);   -- equal?
end;

现在“bye”被写入两次,正如对象引用所预期的那样。诀窍是 o1 和 o2 都包含同一对象的相同索引(〜引用)。语法有点复杂,但在访问属性和方法时仍然与标准对象操作非常相似。

将一个对象分配给其他对象与标准对象分配完全相同:

o2 := o1;

与使用对象作为函数参数相同:

afunc(o1);

在内部,afunc() 将仅使用具有相同特殊语法的 o1 来访问方法或属性(并且无需分配特殊语法):

eo.o(o1).attrib := 5;
eo.o(o1).method('nice');
o3 := o1;

使用此技巧的唯一要求是将散列(类型和变量)添加到我们要封装的每个类的 eo 包中。


Update:基于变量名的索引值:

o1 := 'o1';

例如,如果我们在函数中创建对象,则可能会出现问题,因为该函数必须知道程序其余部分中使用的所有值以避免重复值。解决方案是从哈希大小中获取值:

o1 := eo.o.count;

这给我们带来了另一个问题:哈希内容是持久的(因为它位于包中),因此当我们创建对象时,越来越多的对象将被添加到哈希中(即使对象是由相同的函数创建的)。解决方案是在处理完对象后从哈希中删除该对象:

eo.o(o1) = null;

所以固定的程序是:

create or replace type cla as object        -- complex class
(
    name varchar2(10)
);


create or replace package eo as     -- package to encapsulate objects
    type ao_t                       -- type for hash (associative array)
        is table of cla
        index by varchar2(100);
    o ao_t;                         -- hash of objects
end;


declare
    o1 varchar2(100);
    o2 varchar2(100);
begin
    o1 := eo.o.count;                   -- index based on hash size
    eo.o(o1) := new cla('hi');          -- store new object into the hash
    o2 := o1;                           -- assign object == assign index
    eo.o(o1).name := 'bye';             -- change object attribute

    dbms_output.put_line('eo.o(o1).name: ' || eo.o(o1).name);
    dbms_output.put_line('eo.o(o2).name: ' || eo.o(o2).name);   -- equal?

    eo.o(o1) = null;                    -- remove object
    eo.o(o2) = null;                    -- remove object (redundant)
end;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PL/SQL:有什么技巧可以避免对象的克隆吗? 的相关文章

随机推荐

  • 使用 C# 快速获取 Active Directory 中的组成员列表

    在网络应用程序中 我们希望显示属于特定组的用户的 sam 帐户列表 在许多情况下 群组可能有 500 名或更多成员 我们需要页面具有响应能力 对于大约有 500 名成员的群组 需要 7 8 秒才能获取该群组所有成员的 sam 帐户列表 有更
  • PHP 邮件:多个收件人?

    我有这个代码 在我的表
  • 如何将用户的多个值存储到特定大小的数组?

    我正在尝试从用户那里获取值并将其存储在特定大小的数组中 我的代码看起来像 int n int parse Console ReadLine string samples Console ReadLine Split int scores A
  • Robolectric“需要互联网许可”

    当我使用 Robolectric 创建活动时收到此错误 java lang IllegalArgumentException INTERNET permission is required 这就是我正在做的 Config constants
  • “新的展示位置”有什么用途?

    这里有人用过C 的 placement new 吗 如果是这样 那又是为了什么 在我看来 它只对内存映射硬件有用 Placement new 允许您在已分配的内存中构造一个对象 当您需要构造对象的多个实例时 您可能希望这样做以进行优化 并且
  • Geodjango 管理,显示点域而不是地图

    这可能是一个愚蠢的问题 但我找不到任何明确的答案 如何更改 Django 管理中的显示 以便 Pointfield 不会像 OpenLayer 地图那样显示 而是作为常规输入字段显示 我需要查看长纬度以进行调试 我必须更改字段类型吗 小部件
  • 如何使用 React 中的样式在特定 div 中设置线性渐变和背景图像

    我需要使用 React Js 中的样式在特定 div 上设置线性渐变以及背景图像 我能够获得其中任何一个 我的意思是说图像或线性渐变 但不能同时获得两者 图像将与线性渐变重叠 我尝试了以下解决方案 leftAdArea width 380
  • 依赖性分析工具 - 更新回归测试用例[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 Problem 我想这是一个很常见的问题 添加新代码会导致回归 现有的测试用例变得过时 代码中的依赖关
  • 替换与正则表达式中的字符不匹配的字符

    我有这个正则表达式 private static final String SPACE PATH REGEX a z A Z 0 9 我检查我的字符串是否与此正则表达式匹配 如果不匹配 我想用 替换所有不在这里的字符 我尝试过 privat
  • 未捕获的 URIError:URI 格式错误 - Windows 上的 jquery UI 选项卡

    我在本地 Windows 开发环境中使用 jquery UI 选项卡 我正在用他们测试演示代码 http jqueryui com tabs default div ul li a href tabs 1 Nunc tincidunt a
  • 将 firebase 数据库 url(String) 分配给数据库引用变量?

    我正在尝试将一个包含数据库中某个位置的 url 的字符串分配给 DatabaseReference 类型 例子 String strRef my database url DatabaseReference ref here I want
  • 注意:未定义索引:HTTP_REFERER

    注意 未定义索引 HTTP REFERER http referer SERVER HTTP REFERER 我在教程中使用了这个 看起来还不错 代码还从包含文件中调用它 我应该改变什么 我添加了 print r SERVER 现在页面给了
  • AngularJS中页面刷新或移动到另一个页面后保留下拉值

    让我解释一下我的情况 我的主页中有下拉列表 如果更改了下拉列表 则数据的更改取决于下拉列表的值 如果我刷新页面或移至另一个页面 下拉列表将自动清除 我想在刷新页面或移动到另一个页面后保留下拉列表值 我尝试这样做 但这没有帮助 HTML
  • 将方法转换为静态方法时的内存使用情况

    我开始使用 Resharper 它指示何时使用一种方法could设为静态 将数百个方法转换为静态方法会在很长一段时间内增加内存占用吗 否 更改为静态方法对内存没有影响 第一次引用类型 无论是静态还是非静态 时 都会初始化所有静态成员并运行静
  • 为 Caffe 生成 LMDB

    我正在尝试使用 caffe 我正在使用 python 包装器 构建用于显着性分析的深度学习模型 但我无法理解如何为此目的生成 lmdb 数据结构 我已经浏览了 Imagenet 和 mnist 示例 我明白我应该以以下格式生成标签 my t
  • 如何添加日期时间字段和时间字段

    我必须添加time对现有的价值datetime在 SQL Server 2012 中使用 T SQL 的值 我在想DATEADD http msdn microsoft com en us library ms186819 aspx功能它可
  • 如何在node.js上运行.php脚本

    我使用 wamp 服务器和 node js 来运行我的应用程序 server js 但是当我想执行 php 脚本时 我总是收到错误 POST http localhost 8080 login php 404 Not Found 服务器 j
  • 从 VBA 定义的宏创建 PowerPoint 加载项

    因此 我在 PowerPoint 演示文稿中创建了一个宏 并且希望其他人可以轻松使用该宏 根据我收集的信息 最好的方法是创建一个Add in 我看到几篇文章指出要执行以下操作 但我仍然遇到问题 打开新的 PowerPoint 演示文稿 使用
  • 如何从一个项目创建多个apk?

    我有一个 android 项目 我需要在其中创建多个 apk 每个 apk 之间的唯一区别是包名称 例如 com my package name 和应用程序字符串名称 因此我可以在一台设备上安装该应用程序的多个实例 有更好的方法吗 我考虑过
  • PL/SQL:有什么技巧可以避免对象的克隆吗?

    如果我们将一个对象变量分配给 pl sql 中的其他对象变量 则该对象将被克隆 因为 pl sql 不支持引用 例如 以下代码将打印两个不同的句子 create or replace type cla as object class wou