CRM 365 - 在需要执行验证时阻止 "onSave" 操作 FetchXML 查询

CRM 365 - Blocking the "onSave" operation when validations require FetchXMLQueries be executed

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

我的问题如下:

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

  2. 是否可以有效地停止 Javascript 或使其“休眠”直到 REST API 数据可用?一切都围绕着 SetTimeout 函数,但这是一个非阻塞函数,我的 javascript 当然只是运行它。

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

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

感谢您的宝贵时间和帮助。

我发现了这个 link 并在新的 Dynamics Trial(2020 版本第 2 波)中对其进行了验证,XRM 组件似乎在那里:

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

MSDN 参考:https://docs.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/


编辑,使其不是“link-only”答案

  • 使用 Clone 创建 Xrm.Page.uiXrm.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);
        }
    }
})());

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