CRM 4.0 Relationships Explained

Relationships in CRM 4.0 are quite powerful but hard to understand at first. There are so many moving parts tied to so many places that it is sometimes difficult to predict what the actual outcome is. So here is my attempt to explain a bit further what the relationships enhancements were in CRM 4.0. To start with let’s explain with a diagram what relationship types are available. Note that to determine the actual feasibility of a relationship (e.g. it may be the case that a specific relationship is not possible between an entity pair) you can use our APIs.

One-to-Many System-System (1:N)

In MSCRM 4.0 you can link system entity to another system entity. The child system entity has a lookup field to associate it with a parent system entity.

Self-Referential

In CRM 4.0 you can link An entity to itself. For example a Case can be linked to a master Case.

Multiple Relationships Between Entities

Many of you know about mulitple lookups issues with same entity, now it can be achieved in MS CRM 4.0 e.g the Account entity might have two relationships with a Contact entity – a primary and secondary Contact.

Many-to-Many System-System, System-Custom and Custom-Custom (N:N)

In MSCRM 4.0 this is major requirement for many to many relationship, now it is possible . Not only will this remove the need to build a “joining” entity, but you have control over how the relationships show up in the CRM UI.

Relationships CRM 4.0

Backend

The major architectural changes were that we introduced the notion of many-to-many relationships and self referential relationships. To enable many-to-many relationships we implement intersect entities under the covers. To enable self referential relationships we added a couple of checks to prevent circular parental references and we also redid portions of several system relationships that were hardcoded to be metadata driven to enable system to system and multiple relationships.

Programmability

Of course we had to provide means for programmers to take advantage of all the niceties that we implemented so we had to introduce a couple of new message and attributes and make some changes in the way fetchXml process relationships. Details are on the SDK but here are a couple of quick examples.

Creating new relationships

Yep, you can create brand new relationships (metadata) programmatically using the metadata API. Here is an example on how to create a Many-to-Many relationship. The CrmUtils class is just a wrapper class that a colleague created to create a label for only one language, 1033-English in this case (as you know CRM 4.0 is Multi Language enabled).

public static void addRelatedTest(TitanMiscTests.CrmSdk.CrmService service)
{
//Links (relates) an account record to a lead record in a manyToMany relationship
Moniker moniker1 = new Moniker();
moniker1.Name = "account";
moniker1.Id = new Guid("4BD77CC1-8D6B-DC11-B026-0017A41E8C1D");
Moniker moniker2 = new Moniker();
moniker2.Name = "lead";
moniker2.Id = new Guid("D1CAB380-C56B-DC11-B026-0017A41E8C1D");
AssociateEntitiesRequest request = new AssociateEntitiesRequest();
request.Moniker1 = moniker1;
request.Moniker2 = moniker2;
request.RelationshipName = "new_account_lead_custom";
service.Execute(request);
}

Adding/Removing records for a relationship

To add a new record to a many-to-many relationship you can use the following code. A similar code can be used to remove a record, just use DisassociateEntities message request/response instead of AssociateEntities.

Note that working with N:N relationships is slightly different than working with a One-to-many relationship (for the later you use SetRelated and RemoveRelated messages instead).

    public static void addRelatedTest(TitanMiscTests.CrmSdk.CrmService service)
{
//Links (relates) an account record to a lead record in a manyToMany relationship
Moniker moniker1 = new Moniker();
moniker1.Name = "account";
moniker1.Id = new Guid("4BD77CC1-8D6B-DC11-B026-0017A41E8C1D");
Moniker moniker2 = new Moniker();
moniker2.Name = "lead";
moniker2.Id = new Guid("D1CAB380-C56B-DC11-B026-0017A41E8C1D");
AssociateEntitiesRequest request = new AssociateEntitiesRequest();
request.Moniker1 = moniker1;
request.Moniker2 = moniker2;
request.RelationshipName = "new_account_lead_custom";
service.Execute(request);
}

Retrieving relationships

The following fetch will retrieve all the leads associated with account with name “Foo” in the custom relationship whose intersect entity is “new_account_lead_custom”.

   public static void retrieveEntitiesViaFetch(TitanMiscTests.CrmSdk.CrmService service)
{
string linkFetch = @"











";
string result = service.Fetch(linkFetch);
Console.WriteLine(result);
}

The same query can be accomplished using QueryExpression as follows, note how the query is constructed from bottom to top when compared with fetchXml.


public static void retrieveEntityListFromManyToMany(TitanMiscTests.CrmSdk.CrmService service)
{
//This code will retrieve a list of "leads" associated with the entity "Foo" on the relationship whose intersect entity is "new_account_lead_custom"
//Filter by the specific record that we are looking for
//(In this example we assume that there are no other accounts with the name Foo, otherwise
// if would be recommended to use the account "id" instead of the name.
ConditionExpression conditionName = new ConditionExpression();
conditionName.AttributeName = "name";
conditionName.Operator = ConditionOperator.Equal;
conditionName.Values = new object[1];
conditionName.Values[0] = "Foo";
FilterExpression selectByName = new FilterExpression();
selectByName.Conditions = new ConditionExpression[] { conditionName };
//Create nested link entity and apply filter criteria
LinkEntity nestedLinkEntity = new LinkEntity();
nestedLinkEntity.LinkToEntityName = "account";
nestedLinkEntity.LinkFromAttributeName = "accountid";
nestedLinkEntity.LinkToAttributeName = "accountid";
nestedLinkEntity.LinkCriteria = selectByName;
//Create the nested link entities
LinkEntity intersectEntity = new LinkEntity();
intersectEntity.LinkToEntityName = "new_account_lead_custom";
intersectEntity.LinkFromAttributeName = "leadid";
intersectEntity.LinkToAttributeName = "leadid";
intersectEntity.LinkEntities = new LinkEntity[] { nestedLinkEntity };
//Create Query expression and set the entity type to lead
QueryExpression expression = new QueryExpression();
expression.EntityName = "lead";
expression.LinkEntities = new LinkEntity[] { intersectEntity };
RetrieveMultipleRequest request = new RetrieveMultipleRequest();
request.Query = expression;
//Execute and examine the response
RetrieveMultipleResponse response = (RetrieveMultipleResponse)service.Execute(request);
BusinessEntity[] entities=response.BusinessEntityCollection.BusinessEntities;
Console.WriteLine("Total related=" + entities.Length);
}