CRM 365 - 当验证需要执行 FetchXMLQueries 时阻止“onSave”操作

问题描述 投票:0回答:2

CRM365 表单提供

OnSave
事件来执行业务验证。 如果其中一项验证失败,我们可以使用
executionContext.getEventArgs().preventDefault()
来停止记录创建。 验证当前表单的字段固然很好,但是,在某些情况下,验证还必须要求对实体记录执行查询。 例如,创建房间预订必须检查是否存在任何其他预先存在的预订,如果它们重叠则停止。 问题在于 REST API 调用是异步的,需要时间来执行和返回结果。当信息在响应中变得可用时,
OnSave
功能就已经结束,并且记录基本上在没有验证的情况下被保存。

我的问题如下:

  1. executionContext.getEventArgs().preventDefault()
    有相反的吗?我们可以停止保存操作,但是有“允许保存”之类的说法吗? 我尝试过
    formContext.data.entity.save();
    但由于我处于
    OnSave
    事件中,它创建了一个无限循环。对我来说几乎不可想象这个标志可以设置但不能重置。

  2. 是否可以有效地停止 JavaScript 或使其“睡眠”直到 REST API 数据可用?一切都围绕

    SetTimeout
    函数展开,但这是一个非阻塞函数,当然我的 JavaScript 只是运行它。

我确信我不是唯一遇到这种情况的人,它必须是解决这些基于 REST API 的验证的模式。

我应该补充一点,我正在寻找基于客户端的解决方案;所有这些都可以在插件或自定义工作流程中相对容易地实现。

javascript rest validation dynamics-crm-365
2个回答
0
投票

我找到了此链接并在新的 Dynamics Trial(2020 年发布第 2 波)中验证了它,并且 XRM 组件似乎在那里:

参考链接https://community.dynamics.com/crm/b/dynamicscrmdevdownunder/posts/cancelling-save-event-based-on-the-result-of-async-operation

MSDN参考https://learn.microsoft.com/en-us/powerapps/developer/model-driven-apps/clientapi/reference/formcontext-data-entity/addonsave

Save and Close
的附加评论:https://dreamingincrm.com/2017/10/12/cancelling-save-event-based-on-the-result-of-async-operation/


编辑,使其不是“仅链接”答案

  • 使用
    Clone
    创建
    Xrm.Page.ui
    Xrm.Page.data.entity
    的副本 - 这样,如果用户按
    Save and Close
    ,这些对象仍然可用
  • 创建
    saveHandler
    方法,使用
    RetrieveMultiple
    模拟异步验证过程

代码:

Xrm.Page.data.entity.addOnSave((()=>{
    let isSave = false;
    var uiClone = parent.jQuery.extend(true, {}, Xrm.Page.ui);
    var entityClone = parent.jQuery.extend(true, {}, Xrm.Page.data.entity);
 
    var closeHandler = ()=>{
        console.log('local. close blocked.');
    };
 
    var saveHandler = (ev)=>{
            console.log('local. save blocked.');
            Xrm.WebApi.retrieveMultipleRecords('systemuser','$select=fullname,jobtitle,homephone').then(x=>{
                isSave = !x.entities.some(x=>x.homephone == '12345');
                if(isSave){
                    Xrm.Page.data.entity.save = entityClone.save;
                    Xrm.Page.ui.close = uiClone.close;
                    if((typeof ev === 'string' && ev === 'saveandclose') ||
                        (ev.getEventArgs && ev.getEventArgs() && ev.getEventArgs().getSaveMode() === 2)){
                        console.log('saveandclose');
                        entityClone.save('saveandclose');
                    }
                    else{
                        console.log('save');
                        entityClone.save();
                    }
                }
                else{
                    console.log('User with homephone 12345 exists. Save blocked.');
                }
            });
    };
 
    return (e)=>{
        var eventArgs = e.getEventArgs();
        console.log(`DataXml OnSave: ${Xrm.Page.data.entity.getDataXml()}`);
        console.log(`Save Mode: ${eventArgs.getSaveMode()}`);
        if(isSave) {
            console.log('proceed to save');
            Xrm.Page.data.entity.save = entityClone.save;
            Xrm.Page.ui.close = uiClone.close;
            return;
        }
        else{
            Xrm.Page.data.entity.save = saveHandler;
            Xrm.Page.ui.close = closeHandler;
            if(eventArgs.getSaveMode() !== 2){
                eventArgs.preventDefault();
            }
            saveHandler(e);
        }
    }
})());

此代码示例的所有功劳均归原作者所有。


0
投票

如果问题是手动entity.save()发生在异步函数完成之前,只需将save()放在异步响应中,而不是在函数之后。如果需要执行多个异步功能,也可以使用 async/await

© www.soinside.com 2019 - 2024. All rights reserved.