19
votes

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": "[email protected]",
}

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":"[email protected]",
  ....
}

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",
    '[email protected]': '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 [email protected] should be presented somehow different, I've tried [email protected], [email protected], [email protected] - but no effects.

Any ideas?

7
why are you using the web API preview and not the REST endpoint? - Guido Preite
the code should be "[email protected]": "/contacts(f76e4e7c-ea61-e511-80fd-3863bb342b00)" note the / before contacts and the quotation marks (just in case) - Guido Preite
@GuidoPreite I've tried and the error message is: A property 'objectid' which only has property annotations in the payload but no property value is declared to be of type 'Edm.Guid'. In OData, only navigation properties and named streams can be represented as properties without values. - maicher

7 Answers

20
votes

Instead of using [email protected], you have to use [email protected]. This results are in:

"[email protected]": "/contacts(f76e4e7c-ea61-e511-80fd-3863bb342b00)"

To get the list of properties, look under the single-valued navigation properties in the documentation.

9
votes

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.

9
votes

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["[email protected]"] = "/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 the return=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 the OData-EntityId header containing the URI to the created record is not returned

Note: 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,
                }
            ]
    };
5
votes

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:

"[email protected]":"/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.

4
votes

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"}
1
votes

You can use following.

'[email protected]': '/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 [email protected] 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)'

0
votes

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