使用EntityCollection类型和Entity类型的输出参数实例

归志宁无五亩园,读书本意在元元。这篇文章主要讲述使用EntityCollection类型和Entity类型的输出参数实例相关的知识,希望能为你提供帮助。
我是微软Dynamics 365 & Power Platform方面的工程师/顾问罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面的微软最有价值专家(Microsoft MVP),欢迎关注我的微信公众号 MSFTDynamics365erLuoYong ,回复453或者20210811可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!
当我们使用Customer API或者Action要输出集合的话怎么办?我尝试了一下EntityCollection类型的输出参数是个不错的选择。
关于Custom API的介绍请参考我的博文:Dynamics 365的Custom API介绍 ,通过Web API调用函数请参考我的博文:Dynamics CRM 2015/2016新特性之二十三:使用Web API执行函数 。
为了方便演示,我做个绑定类型的Custom API (用Action也是一样),根据一个Account,返回它所有的有效的Contacts,还返回Contact的数量。
【使用EntityCollection类型和Entity类型的输出参数实例】我新建的Custom API截图如下,我将Binding Type设置为了Entity, Bound Entity Logical Name设置为了account,Is Function设置为了Yes。

使用EntityCollection类型和Entity类型的输出参数实例

文章图片


为它定义了两个输出参数,第一个整数类型的输出参数没啥说的,如下截图所示:
使用EntityCollection类型和Entity类型的输出参数实例

文章图片


另外一个参数就是我们要讲的EntityCollection类型的参数,如下:
使用EntityCollection类型和Entity类型的输出参数实例

文章图片


我这个Custom API用到的服务器端代码如下:
using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Query; using System; namespace D365.Plugins { public class CustomAPIGetContactsByAccountId : IPlugin { public void Execute(IServiceProvider serviceProvider) { ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); tracingService.Trace($"Enter CustomAPIGetContactsByAccountId on {DateTime.UtcNow.ToString()}"); IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); IOrganizationService adminOrgSvc = serviceFactory.CreateOrganizationService(null); string fetchXml = string.Format(@"< fetch version=\'1.0\' mapping=\'logical\' distinct=\'false\'> < entity name=\'contact\'> < attribute name=\'fullname\' /> < attribute name=\'telephone1\' /> < attribute name=\'contactid\' /> < order attribute=\'fullname\' descending=\'false\' /> < filter type=\'and\'> < condition attribute=\'parentcustomerid\' operator=\'eq\' value=https://www.songbingjia.com/'{0}\' /> < condition attribute=\'statecode\' operator=\'eq\' value=https://www.songbingjia.com/'0\' /> < /filter> < /entity> < /fetch> ", context.PrimaryEntityId); context.OutputParameters["ly_contacts"] = adminOrgSvc.RetrieveMultiple(new FetchExpression(fetchXml)); var contactEc = adminOrgSvc.RetrieveMultiple(new FetchExpression(fetchXml)); context.OutputParameters["ly_contacts"] = contactEc; context.OutputParameters["ly_countofcontact"] = contactEc.Entities.Count; } } }


我使用javascript通过Web API调用它的代码如下:
var clientUrl = Xrm.Utility.getGlobalContext().getClientUrl(); var req = new XMLHttpRequest() req.open("GET", clientUrl + "/api/data/v9.2/accounts(7076d7bb-3aa3-eb11-b1ac-00224816920b)/Microsoft.Dynamics.CRM.ly_GetContactsByAccountId()", true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.setRequestHeader("OData-MaxVersion", "4.0"); req.setRequestHeader("OData-Version", "4.0"); req.onreadystatechange = function () { if (this.readyState == 4) { req.onreadystatechange = null; if (this.status == 200) { var responseJSON = JSON.parse(this.responseText); console.log(responseJSON); responseJSON.ly_contacts.forEach(element => console.log(element.fullname)); } } } req.send();


返回的内容如下,可以看到返回的EntityCollection类型的输出参数的值是一个数组,包括了其中实体查询出来的元素值。
{ "@odata.context":"https://luoyongdemo.crm5.dynamics.com/api/data/v9.2/$metadata#Microsoft.Dynamics.CRM.ly_GetContactsByAccountIdResponse", "ly_countofcontact":7, "ly_contacts":[ { "@odata.type":"#Microsoft.Dynamics.CRM.contact", "@odata.etag":"W/\\"11141859\\"", "fullname":"Nancy Anderson (sample)", "telephone1":"555-0102", "contactid":"ca76d7bb-3aa3-eb11-b1ac-00224816920b" }, { "@odata.type":"#Microsoft.Dynamics.CRM.contact", "@odata.etag":"W/\\"11141864\\"", "fullname":"Patrick Sands (sample)", "telephone1":"555-0110", "contactid":"da76d7bb-3aa3-eb11-b1ac-00224816920b" }, { "@odata.type":"#Microsoft.Dynamics.CRM.contact", "@odata.etag":"W/\\"11141862\\"", "fullname":"Paul Cannon (sample)", "telephone1":"555-0107", "contactid":"d476d7bb-3aa3-eb11-b1ac-00224816920b" }, { "@odata.type":"#Microsoft.Dynamics.CRM.contact", "@odata.etag":"W/\\"11141863\\"", "fullname":"Rene Valdes (sample)", "telephone1":"555-0108", "contactid":"d676d7bb-3aa3-eb11-b1ac-00224816920b" }, { "@odata.type":"#Microsoft.Dynamics.CRM.contact", "@odata.etag":"W/\\"11141861\\"", "fullname":"Scott Konersmann (sample)", "telephone1":"555-0105", "contactid":"d076d7bb-3aa3-eb11-b1ac-00224816920b" }, { "@odata.type":"#Microsoft.Dynamics.CRM.contact", "@odata.etag":"W/\\"11141860\\"", "fullname":"Sidney Higa (sample)", "telephone1":"555-0104", "contactid":"ce76d7bb-3aa3-eb11-b1ac-00224816920b" }, { "@odata.type":"#Microsoft.Dynamics.CRM.contact", "@odata.etag":"W/\\"11141865\\"", "fullname":"Susan Burk (sample)", "telephone1":"555-0111", "contactid":"dc76d7bb-3aa3-eb11-b1ac-00224816920b" } ] }


你可能会问,如果我要返回的多个实体组合的数据怎么办?比如Contact实体没有的字段怎么办?我的想法是返回的EntityCollection中的Entity的属性我自己定,这个属性不存在也可以,这个可以做到嘛?我尝试了一下,是可以的,我将代码改成如下即可,主要变化是EntityCollection中的Entity不要指定逻辑名称,直接用new Entity()这个没有输入参数的构造函数进行初始化即可。
using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Query; using System; namespace D365.Plugins { public class CustomAPIGetContactsByAccountId : IPlugin { public void Execute(IServiceProvider serviceProvider) { EntityCollection returnVal = new EntityCollection(); ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); tracingService.Trace($"Enter CustomAPIGetContactsByAccountId on {DateTime.UtcNow.ToString()}"); IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); IOrganizationService adminOrgSvc = serviceFactory.CreateOrganizationService(null); string fetchXml = string.Format(@"< fetch version=\'1.0\' mapping=\'logical\' distinct=\'false\'> < entity name=\'contact\'> < attribute name=\'fullname\' /> < attribute name=\'telephone1\' /> < attribute name=\'contactid\' /> < order attribute=\'fullname\' descending=\'false\' /> < filter type=\'and\'> < condition attribute=\'parentcustomerid\' operator=\'eq\' value=https://www.songbingjia.com/'{0}\' /> < condition attribute=\'statecode\' operator=\'eq\' value=https://www.songbingjia.com/'0\' /> < /filter> < /entity> < /fetch> ", context.PrimaryEntityId); context.OutputParameters["ly_contacts"] = adminOrgSvc.RetrieveMultiple(new FetchExpression(fetchXml)); var contactEc = adminOrgSvc.RetrieveMultiple(new FetchExpression(fetchXml)); context.OutputParameters["ly_countofcontact"] = contactEc.Entities.Count; Entity entity; foreach (var item in contactEc.Entities) { //entity = new Entity("contact",item.Id); //如果要自己定义属性,不要指定实体逻辑名称,用下面这行代码即可 entity = new Entity(); entity["fullname"] = item.GetAttributeValue< string> ("fullname"); entity["telephone1"] = item.GetAttributeValue< string> ("telephone1"); entity["notExistStringAttribute"] = DateTime.Now.ToString(); entity["notExistDateAttribute"] = DateTime.UtcNow; returnVal.Entities.Add(entity); } context.OutputParameters["ly_contacts"] = returnVal; } } }

返回的JSON如下,可以看到有自己定义的属性了:
{ "@odata.context":"https://luoweidemo.crm5.dynamics.com/api/data/v9.2/$metadata#Microsoft.Dynamics.CRM.ly_GetContactsByAccountIdResponse", "ly_countofcontact":7, "ly_contacts":[ { "@odata.type":"#Microsoft.Dynamics.CRM.expando", "fullname":"Nancy Anderson (sample)", "telephone1":"555-0102", "notExistStringAttribute":"8/11/2021 2:10:27 PM", "notExistDateAttribute":"2021-08-11T14:10:27.8542352Z" }, { "@odata.type":"#Microsoft.Dynamics.CRM.expando", "fullname":"Patrick Sands (sample)", "telephone1":"555-0110", "notExistStringAttribute":"8/11/2021 2:10:27 PM", "notExistDateAttribute":"2021-08-11T14:10:27.8542352Z" }, { "@odata.type":"#Microsoft.Dynamics.CRM.expando", "fullname":"Paul Cannon (sample)", "telephone1":"555-0107", "notExistStringAttribute":"8/11/2021 2:10:27 PM", "notExistDateAttribute":"2021-08-11T14:10:27.8542352Z" }, { "@odata.type":"#Microsoft.Dynamics.CRM.expando", "fullname":"Rene Valdes (sample)", "telephone1":"555-0108", "notExistStringAttribute":"8/11/2021 2:10:27 PM", "notExistDateAttribute":"2021-08-11T14:10:27.8542352Z" }, { "@odata.type":"#Microsoft.Dynamics.CRM.expando", "fullname":"Scott Konersmann (sample)", "telephone1":"555-0105", "notExistStringAttribute":"8/11/2021 2:10:27 PM", "notExistDateAttribute":"2021-08-11T14:10:27.8542352Z" }, { "@odata.type":"#Microsoft.Dynamics.CRM.expando", "fullname":"Sidney Higa (sample)", "telephone1":"555-0104", "notExistStringAttribute":"8/11/2021 2:10:27 PM", "notExistDateAttribute":"2021-08-11T14:10:27.8542352Z" }, { "@odata.type":"#Microsoft.Dynamics.CRM.expando", "fullname":"Susan Burk (sample)", "telephone1":"555-0111", "notExistStringAttribute":"8/11/2021 2:10:27 PM", "notExistDateAttribute":"2021-08-11T14:10:27.8542352Z" } ] }


如果该Custom API只有一个EntityCollection类型的输出参数,它返回的JSON就会没有输出参数的名称,效果相当于输出参数的名称换成了value,示例如下:
{ "@odata.context":"https://luoweidemo.crm5.dynamics.com/api/data/v9.2/$metadata#expando", "value":[ { "@odata.type":"#Microsoft.Dynamics.CRM.expando", "fullname":"Nancy Anderson (sample)", "telephone1":"555-0102", "notExistStringAttribute":"8/11/2021 2:47:26 PM", "notExistDateAttribute":"2021-08-11T14:47:26.1280783Z" }, { "@odata.type":"#Microsoft.Dynamics.CRM.expando", "fullname":"Patrick Sands (sample)", "telephone1":"555-0110", "notExistStringAttribute":"8/11/2021 2:47:26 PM", "notExistDateAttribute":"2021-08-11T14:47:26.1280783Z" }, { "@odata.type":"#Microsoft.Dynamics.CRM.expando", "fullname":"Paul Cannon (sample)", "telephone1":"555-0107", "notExistStringAttribute":"8/11/2021 2:47:26 PM", "notExistDateAttribute":"2021-08-11T14:47:26.1280783Z" }, { "@odata.type":"#Microsoft.Dynamics.CRM.expando", "fullname":"Rene Valdes (sample)", "telephone1":"555-0108", "notExistStringAttribute":"8/11/2021 2:47:26 PM", "notExistDateAttribute":"2021-08-11T14:47:26.1280783Z" }, { "@odata.type":"#Microsoft.Dynamics.CRM.expando", "fullname":"Scott Konersmann (sample)", "telephone1":"555-0105", "notExistStringAttribute":"8/11/2021 2:47:26 PM", "notExistDateAttribute":"2021-08-11T14:47:26.1280783Z" }, { "@odata.type":"#Microsoft.Dynamics.CRM.expando", "fullname":"Sidney Higa (sample)", "telephone1":"555-0104", "notExistStringAttribute":"8/11/2021 2:47:26 PM", "notExistDateAttribute":"2021-08-11T14:47:26.1280783Z" }, { "@odata.type":"#Microsoft.Dynamics.CRM.expando", "fullname":"Susan Burk (sample)", "telephone1":"555-0111", "notExistStringAttribute":"8/11/2021 2:47:26 PM", "notExistDateAttribute":"2021-08-11T14:47:26.1280783Z" } ] }


再来看看Entity类型的参数,我这里定义一个Entity类型的输出参数如下,且这个Custom Action只有这个输出参数:
使用EntityCollection类型和Entity类型的输出参数实例

文章图片


我使用的服务器端代码如下:
using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Query; using System; using System.Linq; namespace D365.Plugins { public class CustomAPIGetTop1EntityByMainPhone : IPlugin { public void Execute(IServiceProvider serviceProvider) { ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); IOrganizationService adminOrgSvc = serviceFactory.CreateOrganizationService(null); string fetchXml = string.Format(@"< fetch version=\'1.0\' mapping=\'logical\' distinct=\'false\' top=\'1\'> < entity name=\'account\'> < attribute name=\'name\' /> < attribute name=\'accountid\' /> < attribute name=\'primarycontactid\' /> < filter type=\'and\'> < condition attribute=\'telephone1\' operator=\'eq\' value=https://www.songbingjia.com/'{0}\' /> < /filter> < /entity> < /fetch> ", context.InputParameters["ly_mainphone"]); var accountEc = adminOrgSvc.RetrieveMultiple(new FetchExpression(fetchXml)); Entity entity = new Entity(); if (accountEc.Entities.Any()) { entity["name"] = accountEc.Entities[0].GetAttributeValue< string> ("name"); entity["primarycontactid"] = accountEc.Entities[0].GetAttributeValue< EntityReference> ("primarycontactid"); entity["notExistStringAttribute"] = DateTime.Now.ToString(); entity["notExistDateAttribute"] = DateTime.UtcNow; } context.OutputParameters["ly_entity"] = entity; } } }


我是用的调用代码如下:
var clientUrl = Xrm.Utility.getGlobalContext().getClientUrl(); var req = new XMLHttpRequest() req.open("GET", clientUrl + "/api/data/v9.2/ly_GetTop1EntityByMainPhone(ly_mainphone=@p1)?@p1=\'555-0158\'", true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.setRequestHeader("OData-MaxVersion", "4.0"); req.setRequestHeader("OData-Version", "4.0"); req.onreadystatechange = function () { if (this.readyState == 4) { req.onreadystatechange = null; if (this.status == 200) { var responseJSON = JSON.parse(this.responseText); console.log(responseJSON); } } } req.send();


返回的内容如下,可以看到自定义的不存在的属性也是可以返回。如果只有Entity类型参数的话,Entity的属性就是一级元素了,这个输出参数的名称在返回的JSON中看不到。
{ "@odata.context":"https://luoweidemo.crm5.dynamics.com/api/data/v9.2/$metadata#expando/$entity", "@odata.type":"#Microsoft.Dynamics.CRM.expando", "name":"A. Datum\'& + Corporation (sample)", "notExistStringAttribute":"8/11/2021 2:39:11 PM", "notExistDateAttribute":"2021-08-11T14:39:11.8301173Z", "primarycontactid":{ "@odata.type":"#Microsoft.Dynamics.CRM.contact", "contact":"49a0e5b9-88df-e311-b8e5-6c3be5a8b200", "__DisplayName__":"Adrian Dumitrascu" } }


你可能还会问,如果我要返回的Entity的某个元素需要是数组怎么办?比如说,就是子网格的记录的主属性拼凑的数组,可以用数组来做,类似服务器端如下:
entity["lstStrings"] = new string[] { "111","2222","33333" };


然后返回的效果类似如下,可以额外多出一个以@data.type结尾的元素,这里是 lstStrings@data.type这个元素。
{ "@odata.context":"https://luoweidemo.crm5.dynamics.com/api/data/v9.2/$metadata#expando/$entity", "@odata.type":"#Microsoft.Dynamics.CRM.expando", "name":"A. Datum\'& + Corporation (sample)", "lstStrings@odata.type":"#Collection(String)", "lstStrings":[ "111", "2222", "33333" ], "notExistStringAttribute":"8/11/2021 3:11:58 PM", "notExistDateAttribute":"2021-08-11T15:11:58.6726534Z", "primarycontactid":{ "@odata.type":"#Microsoft.Dynamics.CRM.contact", "contact":"49a0e5b9-88df-e311-b8e5-6c3be5a8b200", "__DisplayName__":"Adrian Dumitrascu" } }



    推荐阅读