Software, Implementation, Training & Support.
One monthly fee.

Build Your Subscription

I recently had an interesting situation with one of our clients who wanted to use a custom entity modeled on the Accounts entity to view their customer data in CRM 2011 and CRM online. The difference was that this entity would have a N:N Relationship with Contacts instead of a 1:N relationship; however, they still wanted to be able to view a rollup of all the Activities and Opportunities from the related Contact and Opportunity records on the custom entity form (see the class diagram below)

df01

Now, CRM makes it really easy to view that for Accounts using the Associated Views but the same cannot be said for custom entities. There were a couple of different options coming  to mind that I knew would achieve the effect– for instance, creating a SSRS report to pull out all the Activities and Opportunities associated with the related Contact and Opportunity records for a particular custom entity record.  Another option would include using JavaScript with Silverlight. The catch though, was that the client wanted to have all the records appear in a standard grid on the entity form.

So, I did some research and found an article that explains a plugin to handle the RetrieveMultiple message. However, this article was written for CRM 4.0, which is significantly different from our target CRM version CRM 2011 or CRM online.  To make it work for the new version, I rewrote the code and utilized the streamline development toolkit provided in CRM SDK 5. The experiment proved successful and I thought it would be helpful to share the solution with other CRM developers out there. Here’s a step by step breakdown of what I did:

Step 1. Create Dynamics CRM 2011 Package project and connect to CRM.

df02

df03

Step 2. In CRM Explorer, right click on the custom entity and select Create plug-in.

df04

Step 3. In the Create Plug-in dialog, select values as below. CRM SDK tool kit will automatically generate a CRM plugin project and the structural code. You just need to implement the PreActivityRetrieveMultiple function as describe in the next step.

df05

Step 4. Implement PreActivityRetrieveMultiple function as below. Some code has been omitted.

[sourcecode language=”csharp”]
protected void ExecutePreActivityRetrieveMultiple(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException(“localContext”);
}
//Get the plugin Execution Context and Organization Service

//find all child entities based on the unsecure configuration XML
foreach (XmlNode child in childentities)
{
string childentityname = child.SelectSingleNode(“./ChildEntityName”).InnerText;
string lookupfield = child.SelectSingleNode(“./Lookup”).InnerText;
string lookupidfield = child.SelectSingleNode(“./Lookupid”).InnerText;

QueryExpression query = new QueryExpression()
{

};

try
{
EntityCollection ec = service.RetrieveMultiple(query);
foreach (Entity childentity in ec.Entities)
childids.Add((childentity[lookupidfield]));
}
catch (SoapException e)
{
throw new Exception(e.Detail.InnerText);
}

}

//add all child entities into the link criteria for the execution context
if (childids.Count == 0) return;
condition.Operator = ConditionOperator.In;
condition.Values.AddRange(childids);

}

}

[/sourcecode]

Step 5. Build and deploy the project. With CRM developer toolkit, you can deploy CRM plugin or custom workflow activity within Visual studio.

df06

Step 6. Test the plugin. Verify the activity associated view in the custom entity. In the standard activities associated view of the custom entity, you should be able to see the activities from child contacts and child opportunities.

df_last

As some might have already noted by now, one of the downsides of working with the CRM SDK 5 is that it’s quite different from previous version and some components in the previous version are no longer supported or changed, which can often frustrate the developer.  However, I feel that it does streamline the development process of CRM plugins and custom workflow activities and can help to improve the development productivity. Developers can also make other CRM development and customization within Visual Studio.

 

Interested in receiving more insights like this by email?

Get the Newsletter

Comments

  1. Thanks for sharing this solution. I tried to use this solution with CRM Online, however it failed due to security restrictions when getting the current HTTPContext.

    The error is: System.Security.SecurityException: That assembly does not allow partially trusted callers.

    You mentioned in the beginning of the article that this works with CRM Online. How did you get around the security restrictions?

    1. Dave Fan

      Hi Rayan,

      Thanks for reaching out. Glad you found the solution useful!

      To answer your question, I get the callerentityid from the Query in context.InputParameters[“Query”], not from httpcontext. Please see detail in the code snippet below:

      if (localContext == null)
      {
      throw new ArgumentNullException(“localContext”);
      }
      //Get the current plugin Execution Context and Organization Server of the context
      IPluginExecutionContext context = localContext.PluginExecutionContext;

      IOrganizationService service = localContext.OrganizationService;

      if (context.MessageName != “RetrieveMultiple” || context.PrimaryEntityName != “activitypointer”) return;

      QueryExpression resultquery = context.InputParameters[“Query”] as QueryExpression;
      if (resultquery == null) return;
      if (resultquery.LinkEntities.Count == 0) return;
      if (resultquery.Criteria.Conditions.Count > 0) return;
      LinkEntity link = resultquery.LinkEntities[0] as LinkEntity;
      if (link.LinkCriteria.Conditions.Count == 0) return;
      ConditionExpression condition = link.LinkCriteria.Conditions[0] as ConditionExpression;
      if (condition.Values.Count == 0) return;

      Guid callerentityid;

      if (!Guid.TryParse(condition.Values[0].ToString(), out callerentityid)) return;

      XmlNodeList childentities = _settings.SelectNodes(“/Settings/Setting”);

      if (childentities.Count == 0) return;

      List childids = new List();
      childids.Add(callerentityid);

      //find all child entities
      foreach (XmlNode child in childentities)
      {
      string childentityname = child.SelectSingleNode(“./ChildEntityName”).InnerText;
      string lookupfield = child.SelectSingleNode(“./Lookup”).InnerText;
      string lookupidfield = child.SelectSingleNode(“./Lookupid”).InnerText;

      QueryExpression query = new QueryExpression()
      {
      EntityName = childentityname,
      ColumnSet = new ColumnSet(lookupidfield),
      Criteria = new FilterExpression
      {
      FilterOperator = LogicalOperator.And,
      Conditions = {
      new ConditionExpression{
      AttributeName = lookupfield,
      Operator = ConditionOperator.In
      }
      }
      }
      };

      query.Criteria.Conditions[0].Values.AddRange(childids);

      try
      {
      EntityCollection ec = service.RetrieveMultiple(query);
      foreach (Entity childentity in ec.Entities)
      childids.Add((childentity[lookupidfield]));
      }
      catch (SoapException e)
      {
      throw new Exception(e.Detail.InnerText);
      }

      }

      //add in child entities into the link criteria for the execution context
      if (childids.Count == 0) return;
      condition.Operator = ConditionOperator.In;
      condition.Values.AddRange(childids);

      }

      Hope that helps.
      Dave
      dave@catapulterp.com

  2. Mark Z

    Hi Dave,
    Thanks for the idea on how to rollup up activities to other entities that are in a N:N relationship. I’m trying to use this to rollup all activities from a lead record to a contact record that are associated through a N:N table called contactleads, not through a parent child relationship.
    The configuration setting I’m using is:

    contactleads
    contactid
    leadid

    As of right now when I upload the plugin and test it in my dev environment (CRM 2013 on-premise) none of the activities from the lead are showing up in the activity view of the contact. My next step is running the plugin through the debugger to try to see what might be going on.
    So my question is am I right in how I wrote that configuration bit? It looks like you had an N:N table between your custom entity and your contact entity, where as for the opportunity entity it was a 1:N relationship (based on CRM relationship naming conventions).

  3. Mark Z

    Update, I have got it to show the activities associated with the contacts on the lead record activity view with the following configuration.
    “”
    “”
    “contactleads”
    “contactid”
    “leadid”
    “”
    “”
    But when I flip the two fields (contacted with leadid) around the plugin fails on the lead record. What I’m expecting when I make this change is that the plugin should no longer run on lead activity view but in the contact activity view. Either way in the contact activity view nothing more is showing.

  4. Mark Z

    Alright, got it to work. Had to change the view to only include “this record only” on the open activity associated view on the contact record, instead of our default ‘Related “Regarding” Records’ – while on the lead record this option set did not exist. I was missing a catch for when the unsecure string was null, to get the lead record to not fail when viewing its activities when I switched the two fields in the configuration step.

    1. Dave Fan

      Hi Mark,

      I’m glad you got it to work! Thanks for the updates.

      Dave

Leave a Comment

Your email address will not be published. Required fields are marked *

*

Filter:

Archives

Register to recieve the latest ERP & CRM insights