Making CrmWebApi Entity References Suck Less For Creates and Updates
account["[email protected]"] = "/contacts(E15C03BA-10EC-E511-80E2-C4346BAD87C8)";Was it “"@odata.bind” or “@bind.odata”? Was it a forward slash or backward slash? Did the Guid have curly braces?
Yes it’s a small pain, but it is bigger if you normally use field accessors (“entity.field” rather than array accessors: “entity[‘field’]”) because "[email protected]" isn't a valid field name. It’s probably because of my C# background, but I prefer not to use the object array accessor method when possible. So the question is, how to make this syntax better and help me remember it.
On my current project I use David Yack’s CRMWebAPI. It’s simple, and uses standard Promises, so no need for a new library, just polyfill Promises (if you’re using IE 11) and you’re all set. The calls are wrapped by a custom TypeScript library (CrmWebApiLib) to allow for some custom changes, of which, this implementation is one. First, the library defines an Entity Reference class (*Note, this is TypeScript, get it, use it, love it)
export class EntityReference implements ODataFormattable {The class has two public properties, “collectionName” and “id”, and implements the two functions of the ODataFormattable interface, “toODataFromat” and “getODataPropertyName”. The toODataFormat adds the forward slash and formats the guid correctly, and the getODataPropertyName appends the “@data.bind” to the property name parameter.
constructor(public collectionName: string, public id: string) { }
toODataFormat = (): string => {
return `/${this.collectionName}(${CrmWebApiLib.removeCurlyBraces(this.id)})`;
}
getODataPropertyName = (propertyName: string): string => {
return `${propertyName}@odata.bind`;
}
}
The ODataFormattable interface just defines the two functions. Then there is also a User Defined Type Guard to determine if any given object implements the ODataFormattable interface:
export interface ODataFormattable {This then is all used in the prepareForOData function:
toODataFormat(): string;
getODataPropertyName(propertyName: string): string;
}
export function isODataFormattable(arg: any): arg is ODataFormattable {
const formattable = arg as ODataFormattable;
return formattable && formattable.toODataFormat !== undefined && formattable.getODataPropertyName !== undefined;
}
/**It creates a new object, and basically loops through all properties of the data object, copying it over to the new object. If the value of the property is a ODataFormatable, it will update the value as well as the property name. There is then a recursive map call to handle arrays as well (think party lists). prepareForOData is then called from within the create and update methods:
* Loops through properties, searching for any ODataFormattable properties or arrays with ODataFormattable, and updates the format to be OData Friendly
* @param data
*/
function prepareForOData(data: any): any {
const oData = {};
for (const propName in data) {
if (!data.hasOwnProperty(propName)) {
continue;
}
const value = data[propName];
if (isODataFormattable(value)) {
oData[value.getODataPropertyName(propName)] = value.toODataFormat();
} else if (value instanceof Array) {
oData[propName] = value.map(prepareForOData);
} else {
oData[propName] = value;
}
}
return oData;
}
export function create(entityCollection: string, data: any): Promise<any> {And now, these two calls, will result in the same exact request made to the CrmWebApi:
return instance().Create(entityCollection, prepareForOData(data));
}
export function update(entityCollection: string, key: string, data: any, upsert?: boolean): Promise<any> {
if (key.indexOf("{") >= 0 || key.indexOf("}") >= 0) {
key = CrmWebApiLib.removeCurlyBraces(key);
}
return instance().Update(entityCollection, key, prepareForOData(data), upsert);
}
No Bueno
const note = {};
note["notetext"] = CommonLib.getValue(fields.description);
note["[email protected]"] = `/allgnt_locations(${CommonLib.getSelectedLookupId(fields.location)})`;
CrmWebApiLib.create("annotations", note);
Muy Bueno
const note = {
notetext: CommonLib.getValue(fields.description),
objectid_allgent_location: new CrmWebApiLib.EntityReference("allgnt_locations", CommonLib.getSelectedLookupId(fields.location))
};
CrmWebApiLib.create("annotations", note);
Published on:
Learn moreRelated posts
Why Plugin Depth Matters in Dynamics CRM
Plugin development in Dynamics CRM is one of the most advanced and intricate components, requiring deep expertise in the platform's event pipe...
Debunking: Dynamics CRM Destination – How Text Lookup Works
When we want to push data to Dataverse/Dynamics CRM using SSIS – KingswaySoft, usually there are relationships (lookup) that we need to ...
Understanding Activity Party Types in Dynamics 365 CE
Dynamics 365 Customer Engagement features 11 unique activity party types, identified by specific integer values in the ActivityParty.Participa...
Debunking: KingswaySoft Dynamics CRM Source- Output Timezone
Hi! I’m back after so a long hiatus (probably I’ll write the reason for this later 🤣). As [lazy] Developers, we’re most lik...
How to configure donotreply email using Shared mailboxes in Dynamics 365 CE?
This article explains how to create and configure a Shared Mailbox in Microsoft 365 for sending emails to users in Dynamics 365 CE. It details...
Enhancing Knowledge Retrieval with Microsoft Copilot Agents in Dynamics CRM and SharePoint
Studies show that 70% of employees spend unnecessary time searching for information across multiple systems, leading to productivity losses an...
{How to} become MCT Microsoft Certified Trainer on Microsoft Dynamics 365 Customer Engagement step by step instructions
Hello Everyone,Today i am going to share guidelines on becoming Microsoft Certified Trainer on Microsoft Dynamics 365 Customer Engagement or P...
Default Value vs. Current Value in Dynamics 365 CE: Key Differences
In Dynamics 365 CE (Customer Engagement), environment variables are used to manage configuration settings for solutions. When dealing with env...
How to Write and Understand a Dynamics CRM Plugin
Here’s a sample plugin code in Dynamics CRM written in C#, along with a detailed explanation of each line. This plugin will update the "...
Dynamics 365 CE Solution Import Failed in Azure DevOps Pipelines
Got the below error while importing Dynamics CRM Solution via Azure DevOps Pipeline. 2024-12-18T23:14:20.4630775Z ]2024-12-18T23:14:20.74...