问题
This question is related to Microsoft Dynamics CRM 2015, that I'm calling through API.
I create contact entity:
POST [organization URI]/api/data/contacts
Content-Type: application/json; charset=utf-8
Accept: application/json
{
"emailaddress1": "myemail@example.com",
}
It works, I see new record, after I log into the panel. And I can call it through the API:
[organization URI]/api/data/contacts(f76e4e7c-ea61-e511-80fd-3863bb342b00)
{
"@odata.context":"[organization URI]/api/data/$metadata#contacts/$entity",
"@odata.etag":"W/\"460199\"",
...
"contactid":"f76e4e7c-ea61-e511-80fd-3863bb342b00",
"emailaddress1":"myemail@example.com",
....
}
Next thing I want to do, is to add annotation record associated with that contact. Following the guide I call:
POST [organization URI]/api/data/annotations
Content-Type: application/json; charset=utf-8
Accept: application/json
{
"notetext": "TEST",
'contact@odata.bind': 'contacts(f76e4e7c-ea61-e511-80fd-3863bb342b00)'
}
But it returns 400 error:
An undeclared property 'contact' which only has property annotations in the payload but no property value was found in the payload. In OData, only declared navigation properties and declared named streams can be represented as properties without values.
When I call:
POST [organization URI]/api/data/annotations
Content-Type: application/json; charset=utf-8
Accept: application/json
{
"notetext": "TEST",
}
New entity is created, but without a relation to contact.
How to properly compose this POST request? What am I missing here?
I suspect, that contact@odata.bind
should be presented somehow different, I've tried contactid@odata.bind
, object@odata.bind
, objectid@odata.bind
- but no effects.
Any ideas?
回答1:
Instead of using objectid@odata.bind
, you have to use objectid_contact@odata.bind
. This results are in:
"objectid_contact@odata.bind": "/contacts(f76e4e7c-ea61-e511-80fd-3863bb342b00)"
To get the list of properties, look under the single-valued navigation properties in the documentation.
回答2:
I've found this working, but in two requests:
POST [organization URI]/api/data/annotations
Content-Type: application/json; charset=utf-8
Accept: application/json
{
"notetext": "TEST"
}
POST [organization URI]/api/data/contacts(f76e4e7c-ea61-e511-80fd-3863bb342b00)/Contact_Annotation/$ref
Content-Type: application/json; charset=utf-8
Accept: application/json
{
"@odata.id": "[organization URI]/annotations(annotation_id_from_first_request)"
}
Edit:
annotation_id_from_first_request
value is taken form first request's response.
回答3:
Part 1:
MSDN Reference: Deep Insert
You can create entities related to each other by defining them as navigation properties values. This is known as deep insert. As with a basic create, the response
OData-EntityId
header contains the Uri of the created entity. The URIs for the related entities created aren’t returned.
Below code is to create Account (1), create + associate Primary contact (2), create & Associate Opportunity (3) and create + associate Task (4)
POST [Organization URI]/api/data/v8.2/accounts HTTP/1.1
Content-Type: application/json; charset=utf-8
OData-MaxVersion: 4.0
OData-Version: 4.0
Accept: application/json
{
"name": "Sample Account",
"primarycontactid":
{
"firstname": "John",
"lastname": "Smith"
},
"opportunity_customer_accounts":
[
{
"name": "Opportunity associated to Sample Account",
"Opportunity_Tasks":
[
{ "subject": "Task associated to opportunity" }
]
}
]
}
Part 2:
Associating annotation to contact uses the below syntax.
note["objectid_contact@odata.bind"] = "/contacts(C5DDA727-B375-E611-80C8-00155D00083F)";
Refer SO link & blog
Part 3:
Answer to your comment on another answer about annotation_id_from_first_request
:
To get the created record Id in response from last request, you can parse like below:
//get Response from Created Record
entityIdWithLink = XMLHttpRequest.getResponseHeader("OData-EntityId");
//get EntityId from ResponseHeader of Created Record
getEntityId = entityIdWithLink.split(/[()]/);
getEntityId = getEntityId[1];
You can read more
You can compose your POST request so that data from the created record will be returned with a status of 201 (Created).
To get this result, you must use thereturn=representation
preference in the request headers. To control which properties are returned, append the $select query option to the URL to the entity set.
The $expand query option will be ignored if used. When an entity is created in this way theOData-EntityId
header containing the URI to the created record is not returnedNote: This capability was added with December 2016 update for Dynamics 365
MSDN Reference: Create with data returned
Update:
If anyone looking for working payload sample to deep insert a record + annotation, the below is from my project:
data = {
"new_attribute1": "test attribute 1",
"new_attribute2": "test attribute 2",
"new_comments": "test comments",
"new_recordurl": recordURL,
"new_feedback_Annotations":
[
{
"notetext": "Screenshot attached",
"subject": "Attachment",
"filename": file.name,
"mimetype": file.type,
"documentbody": base64str,
}
]
};
回答4:
This answer applies for web api usage:
If the references property has been defined using uppercase letters, you have to use uppercase letters in the property on update and insert. Look at the Schema name in the property list of the primary entity.
Lets say you have an entity called myprefix_entity
with a reference to the account entity, and you named it Account
, and the schema name became myprefix_AccountId
, you would have to refer it as:
"myprefix_AccountId@odata.bind":"/accounts(f76e4e7c-ea61-e511-80fd-000000000000)"
The uppercase A and the uppercase I in myprefix_AccountId
matters, if that is how the schema name has been defined.
回答5:
I'm using this C# Code for creating and linking (the Task.Await stuff is not very clever, so... be careful):
dynamic testAno = new ExpandoObject();
testAno.NoteText = "Hello World!";
testAno.Subject = "Note Subject";
dynamic refAccount = new ExpandoObject();
refAccount.LogicalName = "account";
refAccount.Id = "003CCFC2-4012-DE11-9654-001F2964595C";
testAno.ObjectId = refAccount;
testAno.ObjectTypeCode = refAccount.LogicalName;
var demo = JsonConvert.SerializeObject(testAno);
HttpContent content = new StringContent(demo, Encoding.UTF8, "application/json");
var handler = new HttpClientHandler { UseDefaultCredentials = true };
HttpClient client = new HttpClient(handler);
var test = client.PostAsync(new Uri("http://crm/.../XRMServices/2011/OrganizationData.svc/AnnotationSet"), content).Result;
The JSON is looking like this:
{"NoteText":"Hello World!",
"Subject":"Note Subject",
"ObjectId": {"LogicalName":"account",
"Id":"003CCFC2-4012-DE11-9654-001F2964595C"}
,"ObjectTypeCode":"account"}
回答6:
You can use following.
'contactid_contact@odata.bind': '/contacts(f76e4e7c-ea61-e511-80fd-3863bb342b00)'
In most of the record you will get _contactid_value as a parameter name. So you have to pass like contactid_entityname@odata.bind as a parameter and in the value you have to pass 'EntitySetName' which would be contacts and GUID. '/EntitysetName(GUID)' So the value will be '/contacts(f76e4e7c-ea61-e511-80fd-3863bb342b00)'
回答7:
might be a bit late for this, but the answer in the following link explains how the binding works really well.
basically, you need to use the field schema name with the suffix @odata.bind and the value being "/entityschemaname(recordGUID)" good to remember that the entityschemaname needs to have an 's' and the recordGUID should not have the curly brackets.
for more information follow this link below where i got this information from
'An undeclared property' when trying to create record via Web API
来源:https://stackoverflow.com/questions/32761311/create-annotation-to-a-contact-entity-in-microsoft-dynamics-crm-by-api