Working with OrganizationService and Relationships – Associate and Disassociate methods

In the last blog post on the topic of working with organization data by using OrganizationService, we will explore its last two methods: Associate and Disassociate. After we saw how we can retrieve data records from CRM, create new records, update and delete existing ones, we’ll examine how we can create and remove relationships between existing records.

Associate

The Associate method creates relationship or associates, as the name itself denotes, between existing entity records. Due to often misunderstanding of phrase “create relationship”, let’s clear that up: it does not assume creating relationship between entities, since that would include changes in metadata, but it rather creates instances of existing relationships. For example, if relationship exists (and by default it exists) between Lead and Competitor entity, then we can use Associate method to create relationship between one (or many) specific Lead record and one (or many) specific Competitor record. On the other side, this method cannot be used between Lead and Product records if relationship between these two isn’t created manually.

Before going into deep how Associate method works, we will examine its definition first:

void Associate(string entityName, Guid entityId, Relationship relationship, EntityReferenceCollection relatedEntities);

As we can see, it doesn’t return any value even though it would be expected to return collection of relationship records that were created. Let’s see what each input parameter means:

  • entityName – it is a string value representing logical name of an entity. Entity specified by this value is the entity that exists in relationship whose records we are creating.
  • entityId – a Guid value used to identify entity record for which the relationship is being created. It needs to be record of entity specified by entityName value. Clearly, Associate method allows us only to create 1-to-1 and 1-to-N relationships in one transaction. Related entities’ records will be associated to the record specified by this value.
  • relationship – this is the instance of Microsoft.Xrm.Sdk.Relationship class. It is C# representation of CRM relationships, just as Microsoft.Xrm.Sdk.Entity is C# representation of CRM entities. Each relationship is uniquely identified by its Schema Name (i.e. “contactleads_association” for N-to-N relationship between leads and contacts) and therefore that value (as a string) should be passed to constructor of relationship object. Alternatively, schema name can be later on set or changed by Relationship’s attribute: SchemaName. Each relationship is identified by Schema Name, but it is actually defined by two entities that are associated (i.e. Lead and Contact) and by type of relationship between them (1-to-N or N-to-N). It also has some other features, such as type of behavior, but these two are the deterministic ones. By passing object of Relationship to Associate method, we basically determine instances of which relationship will be created by calling this method. entityName, which is the first input parameter, needs to be one of two entities existing in this relationship.
  • relatedEntities – this is collection of related entity records that will be associated to entity record specified by entityId parameter. They all need to be records of entity which exists in relationship specified by relationship parameter. These records are determined by object of one specifically designed class from Microsoft.Xrm.Sdk: EntityReferenceCollection. It is similar to EntityCollection which we met as a type of return value of retrieveMultiple method. This is basically object representing collection of entity references and C# List of EntityReference objects can be extracted from it, but EntityReferenceCollection can also be constructed by passing the List of EntityReference objects to its constructor. Since each entityReference object is a representation of certain entity record from CRM, EntityReferenceCollection is a good way to specify which records will be associated to the primary record – record specified by entityId parameter.

Associate method is primarily designed to work with 1-N relationships. Executing this method will create relationship of primary entity record (1) with the list of related entity records (N). However, the method will work fine with N-to-N relationships as well. Relationship specified as method’s argument can be N-to-N relationship, but the limitation is that in one transaction (by one call of method), only 1-to-N relationships, as a subset of N-to-N relationship, can be created. For instance, by default, N-to-N relationship between Contacts and Leads exists. Associate method can, in one transaction, create relationship between one specific Contact and several Leads or between one lead and several Contacts. If there is need to create relationship between N contacts and M leads, then Associate method ought to be called N times – once for each contact.

Exception thrown by the method can be caused by passing non-existing parameters: non-existing entity, invalid or non-existing Guid of primary entity, non-existing entity references on related entity records or invalid schema name of the relationship. In all other cases, Associate method should be exception-safe. In case that, in 1-to-N relationship, related entity record has already relationship with primary entity record, that relationship will be overwritten by Associate method call, if the method aims on that relationship between those specific records. No exception will be casted. For example, if a contact works at Account 1 and Associate method creates relationship between that contact and Account 2, relationship between the contact and Account 1 will simply be overwritten with the new relationship.

Let’s see the example of retrieving all contacts from Seattle and one account and creating relationship between them.

Will create account called „Ajdin’s Company“ and three contacts „Example Person 1“, „Example Person 2“ and „Example Person 3“ whose address is in Seattle.

"Ajdin's Company" account with no contacts

“Ajdin’s Company” account with no contacts

"Example Person 1" contact with no account

“Example Person 1” contact with no account

Now we will execute following code which will retrieve all contacts from Seattle and retrieve the account called „Ajdin’s Company“. Associate method will be called using „Ajdin’s company“ as primary entity record, contacts as related entity records, and “contact_customer_accounts” as relationship.

 QueryExpression query = new QueryExpression("contact");
 query.ColumnSet = new ColumnSet(true);
 FilterExpression filter = new FilterExpression();
 filter.Conditions.Add(new ConditionExpression("address1_city", ConditionOperator.Equal, "Seattle"));
 query.Criteria = filter;
 DataCollection<Entity> contacts = orgService.RetrieveMultiple(query).Entities;
query = new QueryExpression("account");
query.ColumnSet = new ColumnSet(true);
filter = new FilterExpression();
filter.Conditions.Add(new ConditionExpression("name", ConditionOperator.Equal, "Ajdin's Company"));
query.Criteria = filter;
DataCollection <Entity> entities = orgService.RetrieveMultiple(query).Entities;
Entity account = entities[0];

List<EntityReference> entityReferences = new List<EntityReference>();
foreach (Entity contact in contacts) entityReferences.Add(contact.ToEntityReference());

orgService.Associate("account", account.Id, new Relationship("contact_customer_accounts"), new EntityReferenceCollection(entityReferences));

“Ajdin’s Company” got 7 new contacts and each of those contacts got “Ajdin’s Company” as their own company.

"Ajdin's Company" account with 7 contacts

“Ajdin’s Company” account with 7 contacts

"Example Person 1" with "Ajdin's Company" as account

“Example Person 1” with “Ajdin’s Company” as account

Disassociate

Disassociate method  of OrganizationService removes relationships between several entity records if the relationships exists. The method has the same definition as Associate method:

void Disassociate(string entityName, Guid entityId, Relationship relationship, EntityReferenceCollection relatedEntities);

Meaning of all input parameters is the same as input parameters of Associate method: entityName is the name of primary entity in the relationship, entityId is the Id of primary entity record, relationship is the object representing specific relationship and relatedEntities is the collection of related entity records. For more detailed meaning of each of them, please see Associate method. By the call of Disassociate method, relationships existing between primary entity record (specified by entityId) and related entity records (specified by relatedEntites) will be removed. Dissasociate method, the same as Associate method, is void method, meaning that it does not have return value.

Important thing to notice is that, if some or all relationships specified by input parameters does not exist, exception will not be thrown. Those relationships will only be ignored. On the other side, the same cases that cause throwing exception from Associate method, will also cause throwing exception from disassociate method.  Those cases mainly included passing invalid input parameters or parameters referencing non-existing records in CRM.

Let’s see the example of removing relationships created in previous code sample.

                    QueryExpression query = new QueryExpression("contact");
                    query.ColumnSet = new ColumnSet(true);
                    FilterExpression filter = new FilterExpression();
                    filter.Conditions.Add(new ConditionExpression("address1_city", ConditionOperator.Equal, "Seattle"));
                    query.Criteria = filter;
                    DataCollection<Entity> contacts = orgService.RetrieveMultiple(query).Entities;

                    query = new QueryExpression("account");
                    query.ColumnSet = new ColumnSet(true);
                    filter = new FilterExpression();
                    filter.Conditions.Add(new ConditionExpression("name", ConditionOperator.Equal, "Ajdin's Company"));
                    query.Criteria = filter;
                    DataCollection <Entity> entities = orgService.RetrieveMultiple(query).Entities;
                    Entity account = entities[0];

                    List<EntityReference> entityReferences = new List<EntityReference>();
                    foreach (Entity contact in contacts) entityReferences.Add(contact.ToEntityReference());

                    orgService.Disassociate("account", account.Id, new Relationship("contact_customer_accounts"), new EntityReferenceCollection(entityReferences));

Result of execution of this code restored the state before calling associate method.

"Ajdin's Company" account with no contacts

“Ajdin’s Company” account with no contacts

"Example Person 1" contact with no account

“Example Person 1” contact with no account

With these two methods, we have finished thorough examination of OrganizationService and its methods. In blog post 1, we talked about setting up connection from .NET project to CRM data, while from blog post 2 to blog post 4, we examined each of its methods in details, stating input parameters, return values, the way of calling methods, context of usage and possible exceptions. With that, post series aimed to fully present how CRM data could be accessed from .NET project. In the other blog posts on powerxrm.com blog, you can find out more how to access data through other end-points by usage of other technologies and from other types of project.