In previous articles I’ve discussed the 365 SDK, creating a connection to the server via the IOrganizationService, and usage of the entity class. Once you have those key elements, it’s really easy to perform create, retrieve, update, and delete (CRUD) operations. I would suggest reviewing those articles before proceeding with this one if you haven’t already. I’m using late bound (and not early bound) here, check out the previous articles for my reasoning and an extended discussion of the merits of either approach.
The complete code sample is on GitHub, see Woodsworkblog.ConsoleApp, for this example see the LateBound class.
To create a record, you first need to create your entity object. Provide the entity schema name, and add any attributes you want to set.
Entity contact = new Entity("contact"); contact["firstname"] = "James"; contact["lastname"] = "Wood";
You then simply call the create function on your service. The create function takes a single parameter of entity. It returns the record id of the newly created record. The entity object you passed as an argument will not have its id automatically populated.
IOrganizationService service = MakeService(); Guid contactId = service.Create(contact);
If you need to create a set of related records, you just need to create them in order of child to parent. Using the first record id as an argument in an entity reference.
Entity account = new Entity("account"); account["name"] = "James Account"; account["primarycontactid"] = new EntityReference("contact", contactId); service.Create(account);
There are two types of retrieve in 365. Retrieving a single record; which you can only do when you already know the record id. Retrieving multiple records using a search condition. In this article I’ll be looking at a simple retrieve.
Provide the schema name of the entity you want to retrieve, the record id, and a column set. The column set specifies the columns you want to retrieve for the record. This will return an entity object, it’s always populated with a couple of extra fields beyond your column set, namely the record id. You can then retrieve values from the entities attribute collection.
Entity contact = service.Retrieve("contact", contactId, new ColumnSet("lastname", "middlename")); return contact.GetAttributeValue<string>("lastname");
If you are feeling extravagant, you can use an alternative column set constructor which takes a bool. Setting true will cause 365 to return all attributes for that record. This is often considered bad practice as you will be causing 365 to load more data from SQL than you actually require.
Only attributes that are populated in 365 will be returned in an entities attributes collection. This is the hazard in using the entity attribute indexer, missing keys due to null data in CRM will result in exceptions. Use the GetAttributeValue function instead, missing keys will then be returned as null for classes, or for structs the default value.
contact["middlename"]; //middle name is not populated in 365. Exception thrown; Generic.KeyNotFoundException contact.GetAttributeValue<string>("middlename"); //returns null
Update is very similar to create. Create your entity object, and set your fields. The attributes will override any existing value in 365, even if you are resetting the same value – this can cause workflows or plugins to execute. You also need to supply the id of the record you wish to update, I normally use the constructor but you can also set the id property on the entity object directly.
Entity contact = new Entity("contact", contactId); contact["firstname"] = "Georgia"; contact["lastname"] = "Wood";
Then call the update function on the service, unlike create there is no return value.
The easiest method to use, delete will remove a record from 365, there isn’t an undo function, so be careful. Simply supply the entity schema name and record id to the service delete function, there is no return value.
When is a field required?
In general, required fields are only enforced on the CRM user interface, this means you can often create or update records via the SDK without populating required fields. However, as always with 365 there are some special cases, fields that are mandatory at the platform level, i.e. last name on the contact. If you don’t populate these the IOrganizationService will throw an exception.