如何复现Oracle APEX Form - Automatic Row Processing (DML)的约束校验逻辑用于批量插入
Oracle APEX 自定义批量插入进程的校验实现方案
背景说明
我之前编写过遍历APEX项的相关实现,后续基于该逻辑开发了自定义PL/SQL进程,实现循环遍历项执行批量插入功能。
现有批量插入代码
BEGIN FOR i IN apex_application.g_f01.FIRST..apex_application.g_f01.LAST LOOP INSERT INTO vue_articles ( nom_article, fk_categorie_article, fk_amortissement, prix_unitaire_article, pk_fk_etage_bureau, commentaire_article ) VALUES ( :P24_NOM_ARTICLE, :P24_FK_CATEGORIE_ARTICLE, :P24_FK_AMORTISSEMENT, TO_NUMBER(:P24_PRIX_UNITAIRE_ARTICLE,'FM999G999G999G999G990D00C'), :P24_PK_FK_ETAG_BUREAU, apex_application.g_f01(i) ); END LOOP; END;
遇到的问题
当前功能运行正常,但缺少约束校验能力:
- 常规表单点击CREATE按钮时,会执行提交页面动作,触发SQL INSERT数据库操作,调用默认进程
Form - Automatic Row Processing (DML),如果输入为空、数值超出范围会自动弹出错误提示; - 自定义进程执行插入时如果值非法,不会返回任何错误提示,插入直接失败,用户无法感知问题原因。
需要实现的能力: - 复现默认自动进程的校验逻辑,实现相同的约束、数值校验能力
- 或是调整现有自定义进程代码,在插入前完成表单所有输入项的校验
- 也可以接受前端校验方案,实现和默认效果一致的字段下错误提示,或是设置校验不通过时禁用提交按钮
附加结构信息
物品表结构
CREATE TABLE inv_tb_article( pk_article INT, date_ajout_article DATE DEFAULT SYSDATE CONSTRAINT ct_nn_date_ajout_article NOT NULL, nom_article VARCHAR(50) CONSTRAINT ct_nn_nom_article NOT NULL, prix_unitaire_article NUMBER(7,2) CONSTRAINT ct_nn_prix_unitaire_article NOT NULL, montant_amorti_article REAL, prix_net_article REAL, fk_amortissement INT, fk_categorie_article INT CONSTRAINT ct_nn_fk_categorie_article NOT NULL, commentaire_article VARCHAR(50), CONSTRAINT ct_pk_article PRIMARY KEY(pk_article), CONSTRAINT ct_fk_amortissement FOREIGN KEY(fk_amortissement) REFERENCES inv_tb_amortissement(pk_amortissement), CONSTRAINT ct_fk_categorie_article FOREIGN KEY(fk_categorie_article) REFERENCES inv_tb_categorie(pk_categorie), CONSTRAINT ct_ck_prix_unitaire_article CHECK(prix_unitaire_article BETWEEN 0 AND 100000) ); ALTER INDEX ct_pk_article RENAME TO ind_pk_article; CREATE INDEX ind_fk_amortissement ON inv_tb_article(fk_amortissement); CREATE INDEX ind_fk_categorie_article ON inv_tb_article(fk_categorie_article); CREATE INDEX ind_nom_article ON inv_tb_article(nom_article);
关联视图定义
插入操作是在多表关联视图VUE_ARTICLES上执行,已为视图配置基础INSTEAD OF触发器,视图定义如下:
CREATE OR REPLACE VIEW VUE_ARTICLES AS select PK_ARTICLE, DATE_AJOUT_ARTICLE, NOM_ARTICLE, FK_CATEGORIE_ARTICLE, FK_AMORTISSEMENT, PRIX_UNITAIRE_ARTICLE, MONTANT_AMORTI_ARTICLE, PRIX_NET_ARTICLE, PK_FK_SERVICE, PK_FK_ETAGE_BUREAU, CODE_SERVICE, code_active_directory, fk_batiment, nom_departement, commentaire_article, ctrl_aj_date, ctrl_aj_user, ctrl_mo_date, ctrl_mo_user, ctrl_mo_jeton, nom_categorie from INV_TB_ARTICLE INNER JOIN inv_tb_posseder ON inv_tb_article.pk_article = inv_tb_posseder.pk_fk_article INNER JOIN inv_tb_service ON inv_tb_posseder.pk_fk_service = inv_tb_service.pk_service INNER JOIN inv_tb_departement ON inv_tb_service.fk_departement = inv_tb_departement.pk_departement INNER JOIN inv_tb_etage_bureau ON inv_tb_posseder.pk_fk_etage_bureau = inv_tb_etage_bureau.pk_etage_bureau INNER JOIN inv_tb_batiment ON inv_tb_etage_bureau.fk_batiment = inv_tb_batiment.pk_batiment INNER JOIN inv_tb_categorie ON inv_tb_article.fk_categorie_article = inv_tb_categorie.pk_categorie;
最终实现方案
我已经通过JavaScript实现了前端校验功能,按钮点击时先清空历史错误,检查必填项是否为空、单价是否在1到99999.99区间,校验通过后弹出确认框,确认后触发批量插入事件,实现效果和默认校验一致,代码如下:
apex.message.clearErrors(); var chkErr = 0; var arr = [ 'P24_NOM_ARTICLE', 'P24_FK_CATEGORIE_ARTICLE', 'P24_BATIM', 'P24_PK_FK_ETAG_BUREAU', 'P24_PRIX_UNITAIRE_ARTICLE' ]; var arrLabel = [ "物品名称", "分类", "建筑", "楼层-办公室", "单价" ]; // 空值校验 for (var i in arr) { if ($v(arr[i]).length == 0) { apex.message.showErrors([ { type: apex.message.TYPE.ERROR, location: ["inline", "page"], pageItem: arr[i], message: arrLabel[i] + "不能为空", unsafe: false } ]); chkErr = 1; } } var str = $v("P24_PRIX_UNITAIRE_ARTICLE"); // 移除货币格式掩码中的'CHF'标识 str = str.slice(0, -3); if (parseFloat(str.replace(/[^\d\.]/g,'')) > 99999.99 || parseFloat(str.replace(/[^\d\.]/g,''))<1){ apex.message.showErrors([{ type: apex.message.TYPE.ERROR, location: ["inline", "page"], pageItem: "P24_PRIX_UNITAIRE_ARTICLE", message: "单价不在合法的取值范围内", unsafe: false} ]); chkErr = 1; } if ( chkErr == 0 ) { /* 校验无错误时触发自定义动态动作 */ apex.message.confirm("您即将插入"+ apex.item('P24_NB_MULT').getValue() + "条物品数据,请确认输入信息是否正确?", function(okPressed) { if (okPressed) { $.event.trigger("insertionMultipleComm"); } }); }
目前该方案已正常运行,效果和默认校验一致。
内容的提问来源于stack exchange,提问作者ThomasT
相关产品推荐
相关产品推荐

