• 使用JS通过Web API执行批量操作,多个操作是一个事务!


    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复235或者20161105可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong.me 。

    Dynamics CRM的Web API新增了一个功能,就是 Execute batch operations using the Web API ,我也参考了
    pham.hongnghiep 的文章 involve Batch Operation CRM 2016 Web Api ,这个功能在某些情况下可能很有用。因为它能通过JS调用一次Web API执行多个操作(这个操作是指一个动作,比如新增一条记录,删除一条记录等,不是流程类型中的操作),而且这多个操作是同一个事物,都成功或者都失败!这个功能和我前面文章 执行插件的替代方式:用JS调用操作 功能类似,但是不需要创建操作,这个是优点,缺点是构造这个POST请求的内容和解析返回的内容比较复杂,都是文本,不能方便的转换成JSON。
    为了解释这个概念,我虚拟出一个需求:
    1)创建一个罗勇测试实体(ly_test)记录及两个罗勇测试辅助实体(ly_testsub)记录,
    2)为没有关联关系的记录,某个固定的客户增加一个任务
    3更新本批次创建的测试实体的一个字段的值,注意$1的运用,它是引用同一个change set中的增加了Content-ID头创建记录的URL)。
    写代码的时候要注意:
    1. changeset 结尾的时候有 -- ,开始的时候则没有,batch也是。
    2. 创建父子关系的实体记录不要通过batch,通过深度创建即可,可有参考我的博文:Dynamics CRM 中Web API中的深度创建(Deep Insert) .
    3. $1等的引用不能放到request body中的json中,反正我试了不行,也可能是我没有找到正确的方法。
    4. 一个changeset中的一个操作是从 --changeset 部分开始,到下一个--changeset,注意其中Content-ID后面要加空行,真正请求的内容前面要加空行,也就是 Content-Type: application/json;type=entry 后面。
    下面奉上一个完整的代码:
    function submit() {
        var clientURL = Xrm.Page.context.getClientUrl();
        var batchId = getRandomString(12);
        var changesetId = getRandomString(12);
        var requestMsg = ["--batch_" + batchId];
        requestMsg.push("Content-Type: multipart/mixed;boundary=changeset_" + changesetId);
        requestMsg.push("");
        requestMsg.push("--changeset_" + changesetId);
        requestMsg.push("Content-Type: application/http");
        requestMsg.push("Content-Transfer-Encoding:binary");
        requestMsg.push("Content-ID: 1");
        requestMsg.push("");
        requestMsg.push("POST " + clientURL + "/api/data/v8.1/ly_tests HTTP/1.1");
        requestMsg.push("Content-Type: application/json;type=entry");
        requestMsg.push("");//注意这里要加空行
        var subMsg1 = {};
        subMsg1.ly_name = "批量操作创建的罗勇测试记录";
        subMsg1["ly_Lookup@odata.bind"] = "/accounts(CE23165A-3AA3-E511-80C7-000D3A807EC7)";
        subMsg1["ly_ly_test_ly_testsub_Test"] = [];
        subMsg1["ly_ly_test_ly_testsub_Test"].push({ "ly_name": "批量操作创建的罗勇测试辅助实体记录1" });
        subMsg1["ly_ly_test_ly_testsub_Test"].push({ "ly_name": "批量操作创建的罗勇测试辅助实体记录2" });
        requestMsg.push(JSON.stringify(subMsg1));
        requestMsg.push("--changeset_" + changesetId);
        requestMsg.push("Content-Type: application/http");
        requestMsg.push("Content-Transfer-Encoding:binary");
        requestMsg.push("Content-ID: 2");
        requestMsg.push("");//注意这里要加空行
        requestMsg.push("POST " + clientURL + "/api/data/v8.1/tasks HTTP/1.1");
        requestMsg.push("Content-Type: application/json;type=entry");
        requestMsg.push("");//注意这里要加空行
        requestMsg.push("{'subject':'批量操作创建的任务','regardingobjectid_account_task@odata.bind':'https://demo.luoyong.me/api/data/v8.1/accounts(C223165A-3AA3-E511-80C7-000D3A807EC7)'}");
        requestMsg.push("--changeset_" + changesetId);
        requestMsg.push("Content-Type: application/http");
        requestMsg.push("Content-Transfer-Encoding:binary");
        requestMsg.push("Content-ID: 3");
        requestMsg.push("");
        requestMsg.push("PATCH $1 HTTP/1.1");
        requestMsg.push("Content-Type: application/json;type=entry");
        requestMsg.push("");//注意这里要加空行
        requestMsg.push("{'ly_singlelinetext':'更新了批量操作创建的罗勇测试实体记录'}");
        requestMsg.push("--changeset_" + changesetId + "--");//changeset结束这里前面不要加空行
        requestMsg.push("");//注意这里要加空行
        requestMsg.push("--batch_" + batchId + "--");//batch结束前面加空行
        executeBatch(clientURL, batchId, requestMsg.join("
    "), function (responseText) {
            Xrm.Utility.alertDialog("执行后返回status=200,也有可能有错误:" + responseText);
        }, function (responseText) {
            Xrm.Utility.alertDialog("执行出错:" + responseText);
        });
    }
    
    function executeBatch(clientURL, batchId, requestMsg, successCallback, errorCallback) {
        var req = new XMLHttpRequest()
        req.open("POST", encodeURI(clientURL + "/api/data/v8.1/$batch", true));//true是异步请求,false是同步请求
        req.setRequestHeader("Content-Type", "multipart/mixed;boundary=batch_" + batchId);
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.onreadystatechange = function () {
            if (this.readyState == 4 /* complete */) {
                req.onreadystatechange = null;
                if (this.status == 200) {//204代表成功无返回值
                    successCallback(this.responseText);
                }
                else {
                    errorCallback(this.responseText);
                }
            }
        };
        req.send(requestMsg);
    }
    
    function getRandomString(len, charSet) {
        charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        var randomString = '';
        for (var i = 0; i < len; i++) {
            var randomPoz = Math.floor(Math.random() * charSet.length);
            randomString += charSet.substring(randomPoz, randomPoz + 1);
        }
        return randomString;
    }
     
    下面是如果使用fiddler模拟的话是如下操作:
    1) POST到的URL是 https://demo.luoyong.me/api/data/v8.1/$batch
    2) 请求头是:注意最后一个Authorization: Bearer 是认证信息,根据实际情况需要的加上。

    Content-Type: multipart/mixed;boundary=batch_AAA1234

    Accept: application/json
    OData-MaxVersion: 4.0
    OData-Version: 4.0
    Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IlRBRzN5S3hrZW04eHppQmpmS3RSUFBoQ1liWSJ9.eyJhdWQiOiJodHRwczovL2RlbW8ubHVveW9uZy5tZS8iLCJpc3MiOiJodHRwOi8vc3RzLmx1b3lvbmcubWUvYWRmcy9zZXJ2aWNlcy90cnVzdCIsImlhdCI6MTQ3ODMwNzM5MiwiZXhwIjoxNDc4MzM2MTkyLCJ1cG4iOiJjcm1hZG1pbkBsdW95b25nLm1lIiwicHJpbWFyeXNpZCI6IlMtMS01LTIxLTY1Mzc0MDc5OC0yNDUxMzM4NTMyLTMwMjU3ODY3ODktMTEwNCIsInVuaXF1ZV9uYW1lIjoiTFVPWU9OR1xcY3JtYWRtaW4iLCJhdXRoX3RpbWUiOiIyMDE2LTExLTA1VDAwOjU2OjMyLjMxM1oiLCJhdXRobWV0aG9kIjoidXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmRQcm90ZWN0ZWRUcmFuc3BvcnQiLCJ2ZXIiOiIxLjAiLCJhcHBpZCI6ImJhMTA2MjY1LWZiM2ItNDllMC1hMGU4LTY4NDBiM2Q3MWFjMiJ9.M8RXfCpBLOoJSazOkmjMIJYyYfYxVGmwojOjO4Pd4Yn9EtbeYK1t0tisP19WTsniHvsRXWaD5bwtLMxQL3DMCOJ1Ftsi7o6gr9U_9URRXffHOqPGOwO5n2Ofxga9pqETi2HPO0PpsyD0hOwMsBkZXCuwjOiYzNdbIY4bq0FDOc4iL7HYTd6xvYAOC8JhNj-H6QuqhrFxRPSrkcKt9Pgkg7T-oblWqZwZEV0sIRbm00pYLSIcPVRiFUmgBQUu7kwqFcwRDgLe7VlSTGlaTRtZphwMB-cYO3LebxDABeMuosZAZPa47g4s8xLpNb5lt9sd365Oebut4jUDhT1VIhNKPw

    3)请求体是:

    --batch_AAA1234
    Content-Type: multipart/mixed;boundary=changeset_BBB4567

    --changeset_BBB4567
    Content-Type: application/http
    Content-Transfer-Encoding:binary
    Content-ID: 1

    POST https://demo.luoyong.me/api/data/v8.1/ly_tests HTTP/1.1
    Content-Type: application/json;type=entry

    {"ly_name":"批量操作创建的罗勇测试记录","ly_Lookup@odata.bind":"/accounts(CE23165A-3AA3-E511-80C7-000D3A807EC7)","ly_integer":10,"ly_ly_test_ly_testsub_Test":[{'ly_name':'批量操作创建的罗勇测试辅助实体记录1'},{'ly_name':'批量操作创建的罗勇测试辅助实体记录2'}]}

    --changeset_BBB4567
    Content-Type: application/http
    Content-Transfer-Encoding:binary
    Content-ID: 2

    POST https://demo.luoyong.me/api/data/v8.1/tasks HTTP/1.1
    Content-Type: application/json;type=entry

    {"subject":"批量操作创建的任务","regardingobjectid_account_task@odata.bind":"https://demo.luoyong.me/api/data/v8.1/accounts(C223165A-3AA3-E511-80C7-000D3A807EC7)"}

    --changeset_BBB4567
    Content-Type: application/http
    Content-Transfer-Encoding:binary
    Content-ID: 3

    PATCH $1 HTTP/1.1
    Content-Type: application/json;type=entry

    {"ly_singlelinetext":"更新了批量操作创建的罗勇测试实体记录"}

    --changeset_BBB4567--

    --batch_AAA1234--

    我帖出一个返回结果,可以看到是普通文本:
     
    文本我粘贴放到下面:

    "--batchresponse_8071c8bc-f577-44a6-a246-e27c1ec027e2
    ?Content-Type: multipart/mixed; boundary=changesetresponse_c5387a7e-c5c6-4ea5-95bd-13df85d67046
    ?
    ?--changesetresponse_c5387a7e-c5c6-4ea5-95bd-13df85d67046
    ?Content-Type: application/http
    ?Content-Transfer-Encoding: binary
    ?Content-ID: 1
    ?
    ?HTTP/1.1 204 No Content
    ?OData-Version: 4.0
    ?Location: https://demo.luoyong.me/api/data/v8.1/ly_tests(6c358f7d-54a3-e611-816b-000d3a80c8b8)
    ?OData-EntityId: https://demo.luoyong.me/api/data/v8.1/ly_tests(6c358f7d-54a3-e611-816b-000d3a80c8b8)
    ?Access-Control-Expose-Headers: Preference-Applied,OData-EntityId,Location,ETag,OData-Version,Content-Encoding,Transfer-Encoding,Content-Length,Retry-After
    ?
    ?
    ?--changesetresponse_c5387a7e-c5c6-4ea5-95bd-13df85d67046
    ?Content-Type: application/http
    ?Content-Transfer-Encoding: binary
    ?Content-ID: 2
    ?
    ?HTTP/1.1 204 No Content
    ?OData-Version: 4.0
    ?Location: https://demo.luoyong.me/api/data/v8.1/tasks(6f358f7d-54a3-e611-816b-000d3a80c8b8)
    ?OData-EntityId: https://demo.luoyong.me/api/data/v8.1/tasks(6f358f7d-54a3-e611-816b-000d3a80c8b8)
    ?Access-Control-Expose-Headers: Preference-Applied,OData-EntityId,Location,ETag,OData-Version,Content-Encoding,Transfer-Encoding,Content-Length,Retry-After
    ?
    ?
    ?--changesetresponse_c5387a7e-c5c6-4ea5-95bd-13df85d67046
    ?Content-Type: application/http
    ?Content-Transfer-Encoding: binary
    ?Content-ID: 3
    ?
    ?HTTP/1.1 204 No Content
    ?OData-Version: 4.0
    ?Location: https://demo.luoyong.me/api/data/v8.1/ly_tests(6c358f7d-54a3-e611-816b-000d3a80c8b8)
    ?OData-EntityId: https://demo.luoyong.me/api/data/v8.1/ly_tests(6c358f7d-54a3-e611-816b-000d3a80c8b8)
    ?Access-Control-Expose-Headers: Preference-Applied,OData-EntityId,Location,ETag,OData-Version,Content-Encoding,Transfer-Encoding,Content-Length,Retry-After
    ?
    ?
    ?--changesetresponse_c5387a7e-c5c6-4ea5-95bd-13df85d67046--
    ?--batchresponse_8071c8bc-f577-44a6-a246-e27c1ec027e2--
    ?"

  • 相关阅读:
    获取文件当前目录及其大小
    PLC工作原理动图,一图搞懂一个原理
    欧拉角的详解
    欧拉角的详解
    PLC/Pragmas
    ASCII码对照表
    C++ 的关键字(保留字)完整介绍
    C++ 基本语法
    pytorch笔记1
    pytorchnum_flat_features(x)
  • 原文地址:https://www.cnblogs.com/luoyong0201/p/Dynamics_365_JavaScript_Execute_Batch_Operations_Web_API.html
Copyright © 2020-2023  润新知