A code app creates account rows and must set each account's primary contact. The developer sets primarycontactid to the contact's GUID string in the create payload, and Dataverse rejects the request. What is the correct way to set this lookup?
Select an answer to reveal the explanation.
Short Explanation
A lookup isn't a text box for a GUID; it's a pointer from one row to another. You point it with the @odata.bind annotation on the navigation property and a path to the target row. The _value property you see on reads looks writable, but it's read-only bait.
Full Explanation
Code apps reach Dataverse through the Web API conventions, and Microsoft's guidance for lookups in code apps is to associate rows through a single-valued navigation property. In the create or update payload, the navigation property name is suffixed with @odata.bind and set to a relative URL of the related row, such as [email protected] with the value /contacts followed by the GUID in parentheses. Dataverse resolves that reference and writes the relationship. Supplying a bare GUID for primarycontactid fails because the property is a navigation property, not a scalar column, so the service rejects the payload. The _primarycontactid_value property is a computed lookup property returned on retrieve; it is read-only and cannot be used to set the relationship. Writing the contact's full name as text has the same type mismatch and adds an unnecessary second request. GUID casing and braces are not the issue; Dataverse accepts standard GUID formats, and the error comes from the property type. Exam caveat: polymorphic lookups such as customer or owner need the entity-specific navigation property and are not yet supported in code apps. Operational check: send a create with the @odata.bind annotation, then retrieve the account with the lookup value property selected to confirm the link.