Oracle APEX - 使用表单提交过程选择要插入的下一行

Posted

技术标签:

【中文标题】Oracle APEX - 使用表单提交过程选择要插入的下一行【英文标题】:Oracle APEX - Selecting next row to insert into using a process on form submit 【发布时间】:2012-01-12 20:41:51 【问题描述】:

好的。我的情况是,我有两家公司 COMPANY1 和 COMPANY2,它们协同工作以创建 PART。由于他们一起工作,他们都拥有所有权,因此都希望将 PART_NUMBER 分配给同一部分。 COMPANY1 为 COMPANY2 提供了一个 PART_NUMBERS 块,以分配给他们创建的部件。

我有一个包含主键 (COMPANY1_PART_NUMBER) 的表 (TABLE_PARTS)。由于 COMPANY1 向 COMPANY2 提供了一组数字,因此表格中只填充了这些数字并等待分配给实际零件。

我有一个 COMPANY2 将使用的输入表单来插入零件信息,包括 COMPANY2_PART_NUMBER。我需要更新 TABLE_PARTS 中的行以填写 pk COMPANY1_PART_NUMBER 周围的其余列,从而将该编号分配给零件。

我已确定我需要选择 MIN(COMPANY1_PART_NUMBER),其中 COMPANY2_PART_NUMBER 为空,并使用零件信息更新该行。

我需要确定表单提交后将使用进程更新哪一行,因为表单会有并发用户,并且在页面加载时选择一行肯定会导致人们不小心尝试插入相同的 COMPANY1_PART_NUMBER 行。

有什么想法吗?我相信这并不难,但我遇到了问题,哈哈。谢谢!

【问题讨论】:

Pfew,我试图理解 :) 我需要澄清一下:公司 1 是否制造零件?创建的零件最终会出现在公司 1 的特定表中,还是像 TABLE_PARTS 这样的“共享”表?当您说公司 1 向公司 2 发送一组数字时,这是什么意思:公司 1 和 2 是否在不同的数据库/模式/...上运行,公司 2 是否知道这些数字是什么,或者是数字只是公司 2 可以为其分配“本地”零件的范围吗?看看这张图片imgur.com/bedo4,这有什么像吗? 这是一个像你的例子一样在'OR'之后的联合表。零件由 COMPANY2 创建和制造。 COMPANY1 帮助设计并拥有 COMPANY2 的部分所有权,因此他们将自己的零件编号应用于 COMPANY2 的零件。因此,TABLE_PARTS 中有一个零件具有来自 COMPANY1 和 COMPANY2 的唯一零件编号。 COMPANY1 为 COMPANY2 提供某个范围的数字块,该范围可能是简单的增量范围,也可能不是。因此,我不能使用序列来增加数字。 COMPANY1_PART_NUMBER 必须在此表或其他表中,并在提交时分配给零件。 COMPANY1_PART_NUMBER 可以分配给任何 COMPANY2_PART_NUMBER,因为 COMPANY1_PART_NUMBER 除了 PN 之外没有任何属性。所以 COMPANY1_PART_NUMBER 需要存储在某个地方,无论是在 TABLE_PARTS 还是其他表中,然后在 COMPANY2 提交零件时需要将它们分配给一行。有意义吗? 内置更新过程要求 PK (COMPANY1_PART_NUMBER) 位于页面上的字段中,这意味着我必须在页面加载时将其分配,但如果有人在其他用户提交之前加载同一页面表单他们将调用相同的 COMPANY1_PART_NUMBER,然后覆盖前一个用户的行。然而,这最终起作用,最重要的是它可靠地为 COMPANY2 的用户提供了唯一的 COMPANY1_PART_NUMBER。当表中没有更多的 COMPANY1_PART_NUMBER 时,它应该返回错误。 好的,我认为现在更清楚了(我希望 x)):有一张桌子,里面只有零件,并且有一个 company2_part_number。公司 2 收到来自公司 1 的编号列表,并将这些编号分配给部件(它只是简单地从该列表中获取一个编号,没有指向特定部件或任何东西的链接,只是一个编号列表)。那么,您是否需要用户在进入表单时能够看到他们将分配的号码? (我认为他们在创建时不会在意,因为数字是“随机的”)我认为在分配后显示它是最重要的。 【参考方案1】:

所以你需要的是:

一个且只有一个用户可以在页面的某处拥有特定的免费部件 ID。不允许用户打开表单,让他们填写详细信息,然后在提交页面后由于其他用户已占用号码等原因导致流程失败。 这已经排除了 apex 中使用的标准机制。并发和丢失更新检查只发生在 DML 处理点,通常在计算和验证之后提交。 我正在考虑标记用户选择进行更新的行。但是,这也必须撤消。只要用户实际单击“取消”按钮就可以了,但是如果没有额外的框架,您将无法捕获其他事件。即使那样,您也只能捕获浏览器事件。如果用户击落浏览器进程甚至崩溃,标记的记录会发生什么!?它只会坐在那里,等待开发人员解决此问题,或者没有意识到他们实际上从未用完数字。 也许可以编写自己的锁定机制:在页面加载时创建锁定。以所选零件 ID 命名此锁,以便对其进行检查。此页面上的另一个 onload 进程应检查输入 id 上的锁定。如果存在锁,则失败并执行某些操作,例如重定向。创建的锁也可以设置超时,因此这实际上可以为崩溃的浏览器和计算机提供备份。然后,当用户取消操作时,您需要移除此锁定。通过面包屑或导航点击离开仍然没有被捕获,但您可以依靠锁定超时。或者使用诸如 Skillbuilders 之类的框架扩展在退出前保存。然后,您可以使用页面进程来移除对不同退出事件的锁定(通过 ajax 调用)。但是,该解决方案仍然不是 100% 最佳的。一个例子是只剩下 1 条记录,而用户想要分配一些东西。但是,由于某种原因,锁仍然超时,因此用户会收到一条错误消息,因此被引导相信没有留下任何 id。同样,这可以通过提供更详细的错误消息来解决,说明还有数字,但当前已锁定(“稍后再试”?- :-/)

这些东西只是在我的脑海中播放。我一直在尝试诸如“选择更新 nowait”之类的东西,但它不起作用。可能是因为一旦运行了块,锁就会被释放。

我希望我能通过谷歌找到一些东西,但真的没有乐趣。我自己还没有遇到这个要求(还没有?),所以我也有点困惑如何最好地解决这个问题。

编辑:我记得我在过去 5 年的某个地方使用过 dbms_locks,也许你应该尝试一下。但是,不能在 apex.oracle.com 上使用 DBMS_LOCK,而且我在工作中的 db 中没有使用它的权限(并且 dba 不在这里)。所以继续看看DBMS_LOCK和this example。

你要做的是:创建一个 onload-after 标头进程,并在那里创建一个独占锁(独占,你当然不想共享任何东西)。您希望此 id 对于所选的部件 id 是唯一的。确保锁定超时(默认为 MAXWAIT = 永远!)或取消释放锁定的过程,这样您就不会在测试它时遇到麻烦。

-- this is just a handle though, not the actual lock
dbms_lock.allocate_unique(lockname        => 'lock_part_'||company1_part_id,
                          lockhandle      => v_lockhandle, 
                          expiration_secs => 300 -- 5 mins
                         ); 

-- request does the actual lock,
-- so this'll give errors when called for the same lockhandle 
-- and a lock is already in effect
v_result := dbms_lock.request(lockhandle => v_lockhandle, 
                              lockmode => dbms_lock.x_mode, 
                              timeout => 0 -- fail instantly and don't wait to put a lock if already locked,
                              release_on_commit => true/false -- try both, not sure if it'll work with TRUE
                             );

release_on_commit 将此参数设置为 TRUE 以释放锁定 提交或回滚。

否则,锁会一直持有,直到它被显式释放或直到 会议结束。

如果一切顺利,由于您创建的锁,另一个会话将无法锁定相同的 ID。捕获错误您必须自己尝试,但不应该对现有锁进行硬测试并为错误提供足够的反馈。

DBMS_LOCK.request 返回值

表 70-10 REQUEST 函数返回值

返回值说明 0 成功 1 次超时 2 死锁 3 参数错误 4 已经拥有由 id 或 lockhandle 指定的锁 5 非法锁柄

我喜欢扩展 apex,但如果您不得不为一页费尽心思,并且有许多不同的流程,所有这些都是针对这一页的自定义...也许有一个简单的方法,我只是我自己也看不到(还)。

【讨论】:

是的,我不希望他们能够选择 COMPANY1_PART_NUMBER... 是什么阻止了两个用户同时单击“分配部件”并获得相同的 COMPANY1_PART_NUMBER?这与在页面加载时使用 SQL 字符串将值简单地调用到 txtbox 有什么不同? 是的,我只是尝试在两个窗口中打开应用程序并在每个窗口中单击“分配零件”,并且都加载了相同的 COMPANY1_PART_NUMBER。它只允许一个人正确提交,但它向两者显示数字。如果我们习惯了桌子怎么办?一个用于存储 COMPANY1_PART_NUMBER,另一个用作 TABLE_PARTS。在插入时,我们是否可以使用进程或触发器从其表中提取下一个 COMPANY1_PART_NUMBER 并将其与 TABLE_PARTS 中的数据一起放入? 是的,这也是我的第一个想法,但我相信你已经有了这个系统 - 所以我尝试了。大约相同的数字:是的,你是对的,onload 过程会做同样的事情,是的,2 个用户可以工作相同的部分。我试图保持简单:) 我不确定如何确保只有一个用户使用特定部分。我想你可以在零件表中使用一个额外的字段,用“X”左右填写,但是你需要在几个地方再次将其空白,并且离开页面不会触发任何事情(除非你想用javascript tbh,我仍然允许不同的用户选择相同的部分,但提交时会失败。然后,您可以预加载另一个零件号。也许不是最佳的,但我会考虑它 好吧,让我们暂时不要过于简单...因为老实说这不符合我的需求。让我们看看我们在上一条评论中提到的解决方案,你说的那个是你的第一个想法。谢谢!

以上是关于Oracle APEX - 使用表单提交过程选择要插入的下一行的主要内容,如果未能解决你的问题,请参考以下文章

提交表单数据不刷新页面oracle apex

Oracle APEX 选择列表

由于日期格式,从 Apex 表单调用 Oracle SP 失败

我想在 ORACLE APEX 的表单中添加非数据库字段

Oracle Apex - 循环项目

Oracle Apex 页面进程不存在条件问题