Working with OrganizationService – Update, Delete and Execute

In the first blog post of this series we examined how we can make connection to our organization data in CRM using OrganizationService class in C# application and in the second blog post we explored methods: Create, Retrieve and Retrieve Multiple that are part of that class. In this blog post on the topic of working with organization data outside the CRM by using OrganizationService, we will explore its additional three methods:

  • Update
  • Delete
  • Execute

Let’s see how they work.

Update

Update method is used for updating already existing record in CRM. Its definition is:

void Update(Entity entity);

Similar to Create method, it also has Entity object as input parameter, but unlike Create method, it doesn’t return anything (its type if void).

Important thing to notice is that existing entity must be passed to the method. Method will check if the entity exists by checking primary key of the entity that is passed to it. Three outcomes are possible:

  1. Primary key of the passed Entity object is not set. Method will throw an exception with appropriate message
  2. Primary key of the passed Entity object is set, but no entity record with that primary key within organization data is found. Method will also throw an exception with message that record does not exist.
  3. Primary key of passed Entity object corresponds to the primary key of entity record within organization data. In that case, all field values of the record will be overwritten with the attribute values of passed Entity object.

The most usual way of updating records is by combining Retrieve (or RetrieveMultiple) and Update methods. One usually first retrieves one or more records, changes values of some attributes and then updates the records. Be aware of multiuser environment in which you will work – it can be possible that your C# application retrieves certain entities which exist in the CRM and while it changes their values, some other user or application deletes those records. When your application calls Update method, it will throw exception since some of those entities does not exist anymore. So it is crucial assumption to execute this method inside try-catch block.

Let’s see example of using Update method.

try {
    string con = "Url=https://URL; Username=USERNAME; Password=PASSWORD;";
    Microsoft.Xrm.Client.CrmConnection connection = Microsoft.Xrm.Client.CrmConnection.Parse(con);
    using(Microsoft.Xrm.Client.Services.OrganizationService orgService = new Microsoft.Xrm.Client.Services.OrganizationService(connection)) {
        QueryExpression query = new QueryExpression();
        query.EntityName = "lead";
        query.ColumnSet = new ColumnSet(true);
        query.Criteria = new FilterExpression();

        ConditionExpression con1 = new ConditionExpression("lastname", ConditionOperator.Equal, "Kahrovic");
        query.Criteria.AddCondition(con1);
        DataCollection < Entity > entities = orgService.RetrieveMultiple(query).Entities;

        foreach(Entity lead in entities) {
            Microsoft.Xrm.Sdk.Money revenue = (Microsoft.Xrm.Sdk.Money) lead["revenue"];
            revenue.Value = 2 * revenue.Value;
            lead["revenue"] = revenue;
            orgService.Update(lead);
        }
    }
} catch (Exception e) {
    Console.WriteLine(e.Message);
}

In this example we used the code from the previous blog post to retrieve all leads with the surname Kahrovic and then we doubled their annual revenues following with updating equivalent records in CRM. Pay attention to the type of revenue – in CRM it is currency type, while in C# it is instance of class Microsoft.Xrm.Sdk.Money. That class has attribute Value which is decimal value of that currency.

 

Delete

Delete method is used for deleting records in CRM. It has following definition:

void Delete(string entityName, Guid id);

It doesn’t have return value as same as Update method. It takes two input arguments: string which represents entity logical name (i.e. lead, account etc.) and Guid which represents primary key/unique Id of entity reocrd that is supposed to be deleted.

If Delete method doesn’t find entity with specified logical name or it doesn’t find entity record with specified Id, it will simply throw an exception with appropriate message. Otherwise, it will delete the record from CRM. Also be aware of possible exceptions due to connection issues or due to multiuser environment, so don’t forget to wrap it inside of try-catch block.

Let’s look at the example that takes the code presented under Update section of this blog post and in foreach loop, instead of doubling revenues of all Kahrovic leads, it deletes those records from CRM. Due to size of the blog post, we will only present here foreach loop.

foreach (Entity lead in entities)
{
     orgService.Delete("lead", lead.Id);
}

 

Execute

The last method for this blog post is execute method. To understand how it works, firstly it needs to be explained that CRM works based on pairs of request and response messages. So, when new record is created, CreateRequest message is sent and CreateResponse message is received or when record is updated, UpdateReuqest is sent and Updateresponse is received.

Execute method is a generic method that can take any request message, execute it and return response message. C# classes from Microsoft.Xrm.Sdk that can successfully model request and response messages are OrganizationRequest and OrganizationResponse classes. Naturally, definition of Execute method is:

OrganizationResponse Execute(OrganizationRequest request);

OrganizationRequest describes the action that needs to be performed and therefore it has two important attributes: RequestName and Parameters. RequestName, which can be set after creating OrganizationRequest or through OrganizationRequest’s constructor is string value representing the name of the action that will be invoked by executing OrganizationRequest. If that action requires some parameters, then they can be set through Parameters attribute which is ParameterCollection, or just by use of [ ] on object of OrganizationRequest in form of: orgRequest[“parameterName”] = “parameterValue”; On the other side, OrganizationResponse has equivalent attributes: responseName that can be read or set as a string value representing the name of the action and results which is a ParameterCollection which can be read as: string result = orgResponse[“resultName”]; or set as orgResponse[“resultName”] = “resultValue”;

However, the usual way to use Execute method is not with OrganizationRequest and OrganizationResponse messages, but rather with their derived classes. In the Microsoft.Xrm.Sdk.Messages and Microsoft.Crm.Sdk.Messages namespaces, there is whole variety of these classes which can be used for most different predefined actions within CRM. The most popular are the ones like: SendEmailRequest / SendEmailResponse which sends e-mail or WhoAmIRequest / WhoAmIResponse which retrieves variety of relevant information on user whose credentials are used when instantiating OrganizationService object. Usually, these derived classes have additional attributes and sometimes even additional methods from which action-specific data can be read or set which can give you more user-rich experience then to use Parameters attribute of OrganizationRequest class and Results attribute of OrganizationResponse class. As I said, the whole bunch of these derived classes can be found in two aforementioned namespaces. Those classes which are part of Microsoft.Xrm.Sdk.Messages namespace come with Microsoft.Xrm.Sdk.dll assembly, while those from Microsoft.Crm.Sdk.Messages come with Microsoft.Crm.Sdk.proxy.dll assembly. They can be installed by using NuGet Package manager, as explained in part 1 of this blog post series.

The whole list of these classes can be found here:

https://msdn.microsoft.com/en-us/library/microsoft.xrm.sdk.organizationrequest.aspx

https://msdn.microsoft.com/en-us/library/microsoft.xrm.sdk.organizationresponse.aspx

Some of them might be the topic of the next blog posts.

Besides invoking predefined actions by using OrganizationRequest and OrganizationResponse or some of their derived classes, user defined actions can be invoked as well by Execute method. Only thing that needs to be done is to specify custom action’s name when creating OrganizationRequest and to set all required parameters. Results attribute from OrganizationResponse object, return from Execute method contains all output parameters of that custom actions. Custom actions are definitely interesting topic for some of following blog posts. Finally, it is important to mention that new derived classes can be generated as well for custom actions by the means of “crmsvcutil” which results in so-called early bound. However, we won’t go deeper then this in this blog post since on the topic of crmsvcutil since it definitely requires separate blog post at least.

For the end of this blog post, let’s see the example from the beginning of this post in which we retrieved all leads with last name Kahrovic and doubled their revenues. We’ll use Execute method instead of RetrieveMultiple and Update methods, in first case using OrganizationRequest and OrganizationResponse and in second case, their derived classes.

try
{
    string con = "Url=https://URL; Username=USERNAME; Password=PASSWORD;";
    Microsoft.Xrm.Client.CrmConnection connection = Microsoft.Xrm.Client.CrmConnection.Parse(con);
    using(Microsoft.Xrm.Client.Services.OrganizationService orgService = new Microsoft.Xrm.Client.Services.OrganizationService(connection))
    {
        QueryExpression query = new QueryExpression();
        query.EntityName = "lead";
        query.ColumnSet = new ColumnSet(true);
        query.Criteria = new FilterExpression();

        ConditionExpression con1 = new ConditionExpression("lastname", ConditionOperator.Equal, "Kahrovic");
        query.Criteria.AddCondition(con1);

        OrganizationRequest orgRequest = new OrganizationRequest("RetrieveMultiple");
        orgRequest["Query"] = query;
        OrganizationResponse orgResponse = orgService.Execute(orgRequest);
        DataCollection < Entity > entities = ((EntityCollection) orgResponse["EntityCollection"]).Entities;

        foreach(Entity lead in entities)
        {
            Microsoft.Xrm.Sdk.Money revenue = (Microsoft.Xrm.Sdk.Money) lead["revenue"];
            revenue.Value = 2 * revenue.Value;
            lead["revenue"] = revenue;

            UpdateRequest updateRequest = new UpdateRequest();
            updateRequest.Target = lead;
            UpdateResponse updateResponse = (UpdateResponse) orgService.Execute(updateRequest);
        }
    }
} catch (Exception e)
{
    Console.WriteLine(e.Message);
}

In the next and final blog post, we will see how to add and how to remove relationships between records of same and different entities – of course, from the C# and by using OrganizationService.