If you’ve used Microsoft’s Dataverse Web API for any length of time, you’re probably familiar with accessing related entities using navigation properties.
Imagine that in our hypothetical world an account can be related to one or more contacts. To fetch the contacts associated with a particular account, you might make a Web API call something like:
GET accounts(00000000-0000-0000-0000-000000000003)/my_account_contacts
(include the "always include" headers)
Nothing surprising so far—but did you know that you can also use navigation properties to create associated entities?
Say you wanted to create a contact that is associated with the above account. One option is to POST (or PATCH) directly to the contacts entity set (i.e. directly to the contact table’s URL). In the request’s JSON body, you’d define the contact to be created, including setting the appropriate relationship field (in this example, my_account) to tie it to the appropriate account:
Request: POST contacts
(include the "always include" headers)
Body:
{
"firstname": "Bob",
"lastname": "Smith",
"my_account@odata.bind": "accounts(00000000-0000-0000-0000-000000000003)"
}
Alternately, you could POST to the account’s navigation property—that is, POST to the exact same URL that was used to fetch the account’s contacts in the first example. In OData terminology, this is known as creating a contained entity.
Request: POST accounts(00000000-0000-0000-0000-000000000003)/my_account_contacts
(include the "always include" headers)
Body:
{
"firstname": "Bob",
"lastname": "Smith"
}
With this approach, there’s no need for the request’s JSON body to set the relationship from contact to account—no need to specify a my_parent value, as was done in the previous example—for the system will automatically infer and set this relationship.
Both of the above contact creation methods are equivalent in their effect: both create a new contact that is related to the same account.
Keep in mind that POSTing to a navigation property always creates a new entity. For collection-valued properties, the new entity will be added to the collection (like the last example, which resulted in the new contact being added to the collection of contacts associated with the account). However, in the case of a single-valued navigation property, there’s no collection to add the new entity to, as the property can point to only one entity. When a new entity is created because a single-valued property is POSTed to, what happens to the entity that the relationship previously pointed to? It’s disassociated but not deleted—it stays around, just with the previous relationship removed.
There you have it: an alternate way to create related entities. Which approach to use is a matter of preference. For collection-valued properties, I find POSTing to the navigation property (a.k.a. creating contained entities) attractive for its symmetry: the same URL is used to both fetch and create related entities.
Note
Don’t forget to include the “always include” headers with every request sent to the Web API.