关注本人微信和易信公众号: 微软动态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("\n"), 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--
?"

使用JS通过Web API执行批量操作,多个操作是一个事务!的更多相关文章

  1. 通过C#代码调用Dynamics 365 Web API执行批量操作

    我是微软Dynamics 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面 ...

  2. 利用Fiddler修改请求信息通过Web API执行操作(Action)实例

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

  3. 不借助工具在浏览器中通过Web API执行Dynamics 365操作(Action)实例

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

  4. 利用Fiddler修改请求信息通过Web API执行Dynamics 365操作(Action)实例

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

  5. 使用RAP2和Mock.JS实现Web API接口的数据模拟和测试

    最近一直在思考如何对Web API的其接口数据进行独立开发的问题,随着Web API的越来越广泛应用,很多开发也要求前端后端分离,例如统一的Web API接口后,Winform团队.Web前端团队.微 ...

  6. 在Web API中使用Swagger-UI开源组件(一个深坑的解决)

    介绍: Swagger-Ui是一个非常棒的Web API说明帮助页,具体详情可自行Google和百度. 官网:http://swagger.io/    GitHub地址:https://github ...

  7. 解决Dynamics 365使用JS调用Web API时报no property value was found in the payload 错误。

    摘要: 微软动态CRM专家罗勇 ,回复323或者20190421可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me! 碰到如下报错: message: "An er ...

  8. A2D JS框架 - Web API CSRF保护实现

    这次自己实现了类似jQuery中ajax调用的方法,并且针对RESTFul进行了改造和集成,实现的A2D AJAX接口如下: $.ajax.RESTFulGetCollection("/ap ...

  9. Asp.Net Web API 2第二课——CRUD操作

    详情请查看http://aehyok.com/Blog/Detail/69.html 个人网站地址:aehyok.com QQ 技术群号:206058845,验证码为:aehyok 本文文章链接:ht ...

随机推荐

  1. DataTable实现分组

    有时候我们从数据库中查询出来数据之后,需要按照DataTable的某列进行分组,可以使用下面的方法实现,代码如下: using System; using System.Collections.Gen ...

  2. Python实现图片的base64编码

    import base64 if __name__ == "__main__": dir='image.jpg' basef=open(dir.split('.')[0]+'_ba ...

  3. css基础,css选择器

    07.29自我总结 css基础 一.什么是CSS CSS是级联样式表 CSS术语标记语言,没有逻辑 CSS作用 完成网页内容的样式与布局 二.CSS的三种引入方式 1. 内联式 书写位置:在 head ...

  4. 从华为“鸿蒙”备胎看IT项目建设

    别误会啊,本文并不在讲大家在做IT项目建设的时候学华为做一个备胎系统,以防正主系统崩掉之后能够及时替换到备胎系统里面,不影响业务. 前段时间华为被美帝制裁,然后各家组织对华为各种限制.然而华为整体布局 ...

  5. Cesium专栏-样条插值(平滑路径、飞行动画,源码下载)

    Cesium Cesium 是一款面向三维地球和地图的,世界级的JavaScript开源产品.它提供了基于JavaScript语言的开发包,方便用户快速搭建一款零插件的虚拟地球Web应用,并在性能,精 ...

  6. Thymeleaf常用语法:条件判断 if、switch case

    if语句条件判断使用th:if,它会判断表达式是否成立,表达式的结果支持boolean.number.character.String及其他类型.满足下面情况,if语句成立:(1) 表达式的结果是数字 ...

  7. Thymeleaf常用语法:模板文件中表达式调用Java类的静态方法

    在模板文件的表达式中,可以使用“${T(全限定类名).方法名(参数)}”这种格式来调用Java类的静态方法. 开发环境:IntelliJ IDEA 2019.2.2Spring Boot版本:2.1. ...

  8. VirtualBox创建的Debian虚拟机与Windows宿主共享文件

    术语: 1.VM:虚拟机 步骤: 1.在Windows10上下载并安装VirtualBox6.0.8(时间:2019/5/30),下载地址:https://download.virtualbox.or ...

  9. Go语言交叉编译工具gox

    基本介绍 交叉编译是为了在不同平台编译出其他平台的程序,比如在Linux编译出Windows程序,在Windows能编译出Linux程序,32位系统下编译出64位程序,今天介绍的gox就是其中一款交叉 ...

  10. 201871010113-刘兴瑞《面向对象程序设计(java)》第十二周学习总结

    项目 内容 这个作业属于哪个课程 <任课教师博客主页链接>https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 <作业链接地址>http ...