Hi all,
Does anybody know if batch requests in CRM 8.2 on premise support reference params? Basically I'm trying to create records in the batch request that depend on records created earlier in the change set.
Per MS documentation "You can use $parameter
such as $1
, $2
, etc to reference URIs used in an earlier changeset in a batch request. This section shows various examples on how $parameter
can be used in the request body of a batch operation to reference URIs." https://docs.microsoft.com/en-us/powerapps/developer/common-data-service/webapi/execute-batch-operations-using-web-api
I have the following function to test
function testBatchRequestReferences() {
var data = [];
var account = { name: "Test Account - bulk entry references" };
var contact = { firstname: "Tester", lastname: "bulk entry" };
account["primarycontactid@odata.bind"] = "$1";
var d = new Date();
var batch = "batch_" + d.toString().replace(/ |:/g, "_").replace(/\(|\)/g, '');
var changeset = "changeset_" + d.toString().replace(/ |:/g, "_").replace(/\(|\)/g, '');
data.push("--" + batch);
data.push('Content-Type: multipart/mixed;boundary=' + changeset);
data.push('');
data.push('--' + changeset);
data.push('Content-Type:application/http');
data.push('Content-Transfer-Encoding:binary');
data.push('Content-ID:' + 1);
data.push('');
data.push('POST ' + parent.Xrm.Page.context.getClientUrl() + '/api/data/v8.2/contacts HTTP/1.1');
data.push('Content-Type:application/json;type=entry');
data.push('');
data.push(JSON.stringify(contact));
data.push('--' + changeset);
data.push('Content-Type:application/http');
data.push('Content-Transfer-Encoding:binary');
data.push('Content-ID:' + 2);
data.push('');
data.push('POST ' + parent.Xrm.Page.context.getClientUrl() + '/api/data/v8.2/accounts HTTP/1.1');
data.push('Content-Type:application/json;type=entry');
data.push('');
data.push(JSON.stringify(account));
data.push("--" + batch);
data.push('Content-Type: multipart/mixed;boundary=' + changeset);
data.push('');
data.push('--' + changeset + '--');
data.push('--' + batch + '--');
var payload = data.join('\r\n');
console.log(payload);
debugger;
//batch insert add all of the entries
$.ajax(
{
method: 'POST',
url: parent.Xrm.Page.context.getClientUrl() + '/api/data/v8.1/$batch',
headers: {
'Content-Type': 'multipart/mixed;boundary=' + batch,
'Accept': 'application/json',
'Odata-MaxVersion': '4.0',
'Odata-Version': '4.0'
},
data: payload,
async: true,
success: function (data, textStatus, xhr) {
console.log("added test entries");
console.log(data);
},
error: function (xhr, textStatus, errorThrown) {
alert(textStatus + " " + errorThrown);
}
});
}
the created payload is this
--batch_Wed_Nov_13_2019_16_20_48_GMT-0800_Pacific_Standard_Time
Content-Type: multipart/mixed;boundary=changeset_Wed_Nov_13_2019_16_20_48_GMT-0800_Pacific_Standard_Time
--changeset_Wed_Nov_13_2019_16_20_48_GMT-0800_Pacific_Standard_Time
Content-Type:application/http
Content-Transfer-Encoding:binary
Content-ID:1
POST cadev.ptclwg.com/.../contacts HTTP/1.1
Content-Type:application/json;type=entry
{"firstname":"Tester","lastname":"bulk entry"}
--changeset_Wed_Nov_13_2019_16_20_48_GMT-0800_Pacific_Standard_Time
Content-Type:application/http
Content-Transfer-Encoding:binary
Content-ID:2
POST cadev.ptclwg.com/.../accounts HTTP/1.1
Content-Type:application/json;type=entry
{"name":"Test Account - bulk entry references","primarycontactid@odata.bind":"$1"}
--batch_Wed_Nov_13_2019_16_20_48_GMT-0800_Pacific_Standard_Time
Content-Type: multipart/mixed;boundary=changeset_Wed_Nov_13_2019_16_20_48_GMT-0800_Pacific_Standard_Time
--changeset_Wed_Nov_13_2019_16_20_48_GMT-0800_Pacific_Standard_Time--
--batch_Wed_Nov_13_2019_16_20_48_GMT-0800_Pacific_Standard_Time--
the response/error i'm getting
--batchresponse_18c1e513-0b61-4eea-a50e-be682570cd06
Content-Type: multipart/mixed; boundary=changesetresponse_fa263bf1-c77f-4401-8d0c-1f0c860b6b16
--changesetresponse_fa263bf1-c77f-4401-8d0c-1f0c860b6b16
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 2
HTTP/1.1 500 Internal Server Error
Access-Control-Expose-Headers: Preference-Applied,OData-EntityId,Location,ETag,OData-Version,Content-Encoding,Transfer-Encoding,Content-Length,Retry-After
Content-Type: application/json; odata.metadata=minimal
OData-Version: 4.0
{
"error":{
"code":"","message":"Resource not found for the segment '$1'.","innererror":{
"message":"Resource not found for the segment '$1'.","type":"Microsoft.OData.Core.UriParser.ODataUnrecognizedPathException","stacktrace":" at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.CreateFirstSegment(String segmentText)\r\n at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.ParsePath(ICollection`1 segments)\r\n at Microsoft.OData.Core.UriParser.Parsers.ODataPathFactory.BindPath(ICollection`1 segments, ODataUriParserConfiguration configuration)\r\n at Microsoft.OData.Core.UriParser.ODataUriParser.Initialize()\r\n at Microsoft.Crm.Extensibility.OData.CrmEdmEntityReference.CreateCrmEdmEntityReference(Uri link, CrmODataExecutionContext context)\r\n at Microsoft.Crm.Extensibility.OData.TypeConverters.EdmEntityTypeConverter.SetNavigationPropertyToXrmEntity(Entity entity, EntityMetadata entityMetadata, IEdmProperty edmProperty, EntityRelationship entityRelationship, Object propertyValue, Nullable`1 role)\r\n at Microsoft.Crm.Extensibility.OData.TypeConverters.EdmEntityTypeConverter.ConvertToCrmTypeInternal(EdmEntityObject edmTypeValue)\r\n at Microsoft.Crm.Extensibility.OData.TypeConverters.EdmTypeConverterBase`2.ConvertToCrmType(Object edmTypeValue)\r\n at Microsoft.Crm.Extensibility.OData.EdmTypeConverter.ConvertToCrmEntity(EdmEntityObject edmEntity, EntityReference entityReference)\r\n at Microsoft.Crm.Extensibility.OData.CrmODataServiceDataProvider.CreateEdmEntity(CrmODataExecutionContext context, String edmEntityName, EdmEntityObject entityObject, Boolean isUpsert)\r\n at Microsoft.Crm.Extensibility.OData.EntityController.PostEntitySet(String entitySetName, EdmEntityObject entityObject)\r\n at lambda_method(Closure , Object , Object[] )\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
}
}
}
--changesetresponse_fa263bf1-c77f-4401-8d0c-1f0c860b6b16--
--batchresponse_18c1e513-0b61-4eea-a50e-be682570cd06
Content-Type: multipart/mixed; boundary=changesetresponse_5eafa4e9-0d6e-4605-8b00-db9bf4b2fd7d
--changesetresponse_5eafa4e9-0d6e-4605-8b00-db9bf4b2fd7d--
--batchresponse_18c1e513-0b61-4eea-a50e-be682570cd06--
Not sure if I'm doing a mistake (doesn't look like it based on MS samples in the link above).
Can anyone please confirm?
Thank you