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

最新文章

  1. lvs-keepalived故障记录
  2. MySQL的热备percona-xtrabackup、innobackupex的安装方法
  3. shell 脚本样例
  4. HDU 2577---How to Type
  5. apache和IIS共享80端口问题
  6. 【LoadRunner】安装LoadRunner时提示缺少vc2005_sp1_with_atl_fix_redist解决方案
  7. Java [Leetcode 337]House Robber III
  8. C语言原码反码补码与位运算.
  9. Java如何获取当前的jar包路径以及如何读取jar包中的资源
  10. 几种MEMS陀螺仪(gyroscope)的设计和性能比较
  11. 【转】gcc/g++ 如何支持c11 / c++11标准编译
  12. Vultr免费vps注册和使用简易教程
  13. Angular.js之指令学习笔记
  14. Android开发学习之路--Android系统架构初探
  15. 20165223《网络对抗技术》Exp2 后门原理与实践
  16. IntelliJ IDEA小问题通过操作软件解决
  17. Linux命令行文本工具
  18. 第九节、人脸检测之Haar分类器
  19. Java 测试连接Oracle数据库是否成功,ojdbc7.jar包下载
  20. Python SSH爆破以及Python3线程池控制线程数

热门文章

  1. C#中类的修饰符
  2. 关于scrapy中scrapy.Request中的属性
  3. llinux/重启/用户切换/注销
  4. Create a Solution using the Wizard 使用向导创建解决方案
  5. FCC---Create a Gradual CSS Linear Gradient
  6. Saltstack_使用指南12_配置管理-jinja模板
  7. Jedis Unexpected end of stream &amp; java.net.SocketException: Broken pipe问题解决思路
  8. (转)vue-router原理
  9. 01. Go 语言简介
  10. 构建LVS负载均衡集群——NAT模式(最简单方式)