I made some investigations and understood that it is possible to do with handling of retrievemultiple message. I developed this plugin for one custom entity and after I decided to make it more flexible with possibility to configure without additional development. Here is the code of plugin:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Crm.Sdk;
using System.Xml;
using Microsoft.Crm.SdkTypeProxy;
using System.Web;
using Microsoft.Crm.Sdk.Query;
using System.Web.Services.Protocols;
namespace RollupActivitites
{
public class RetrieveMultipleHandler : IPlugin
{
#region Privates
private XmlDocument _settings = null;
#endregion Privates
#region CTOR
public RetrieveMultipleHandler(string config, string secureconfig)
{
_settings = new XmlDocument();
_settings.LoadXml(config);
}
#endregion CTOR
#region IPlugin Members
public void Execute(IPluginExecutionContext context)
{
if (context.MessageName != MessageName.RetrieveMultiple || context.PrimaryEntityName != EntityName.activitypointer.ToString())
return;
if (!(context.CallerOrigin is ApplicationOrigin))
return;
HttpContext webcontext = HttpContext.Current;
if (webcontext == null)
return;
string callerentitytype = null;
string callerentityidstring = null;
if (webcontext.Request.Params.AllKeys.Contains("oType"))
{
callerentitytype = webcontext.Request.Params["oType"];
callerentityidstring = webcontext.Request.Params["oId"];
}
else
{
string requeststring = webcontext.Request.UrlReferrer.Query;
requeststring = requeststring.Substring(1);
string[] parts = requeststring.Split(new string[] { "=", "&" }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < parts.Length - 1; i++)
if (parts[i].ToLower() == "otype")
callerentitytype = parts[i + 1];
else if (parts[i].ToLower() == "oid")
callerentityidstring = parts[i + 1];
}
if (string.IsNullOrEmpty(callerentitytype))
return;
Guid callerentityid = new Guid(callerentityidstring.Replace("%7b", "").Replace("%7d", ""));
XmlNodeList childentities = _settings.SelectNodes(string.Format("//Settings/Setting[ParentEntityType={0}]", callerentitytype));
if (childentities.Count == 0)
return;
ICrmService crmservice = context.CreateCrmService(false);
List<object> childids = new List<object>();
foreach (XmlNode child in childentities)
{
string childentityname = child.SelectSingleNode("./ChildEntityName").InnerText;
string lookupfield = child.SelectSingleNode("./Lookup").InnerText;
QueryByAttribute query = new QueryByAttribute();
query.Attributes = new string[] { lookupfield };
query.ColumnSet = new ColumnSet(new string[] { string.Format("{0}id", childentityname) });
query.EntityName = childentityname;
query.Values = new object[] { callerentityid };
RetrieveMultipleRequest request = new RetrieveMultipleRequest();
request.Query = query;
request.ReturnDynamicEntities = true;
RetrieveMultipleResponse response = null;
try
{
response = crmservice.Execute(request) as RetrieveMultipleResponse;
}
catch (SoapException e)
{
throw new Exception(e.Detail.InnerText);
}
foreach (DynamicEntity childentity in response.BusinessEntityCollection.BusinessEntities)
childids.Add((childentity[string.Format("{0}id", childentityname)] as Key).Value);
}
if (childids.Count == 0)
return;
childids.Add(callerentityid);
QueryExpression resultquery = context.InputParameters[ParameterName.Query] as QueryExpression;
if (resultquery == null)
return;
if (resultquery.LinkEntities.Count == 0)
return;
LinkEntity link = resultquery.LinkEntities[0] as LinkEntity;
ConditionExpression condition = link.LinkCriteria.Conditions[0] as ConditionExpression;
condition.Operator = ConditionOperator.In;
condition.Values = childids.ToArray();
}
#endregion
}
}
To make it work you also have to configure it in the proper way - you should insert configure xml to unsecure configuration of step registration dialogue:
Here are registration parameters:
<?xml version="1.0" standalone="yes"?>
<Settings>
<Setting>
<ParentEntityType>10004</ParentEntityType>
<ChildEntityName>custom_child</ChildEntityName>
<Lookup>custom_parentid</Lookup>
</Setting>
</Settings>
ParentEntityType is code of entity from which you want see activities of child entities.
ChildEntityName is scheme name of child entity.
Lookup is the relational field between parent and child entities.
Result of work of this plugin:
Activities of child entity.
Activities of parent entity.
This plugin work for History too.
You can download source code and compiled assembly here:
Hi Andriy,
ReplyDeleteI am trying to implement this solution in CRM 2011. I have registered plugin on RetrieveMultiple message on activitypointer, Plugin triggering only when i am viewing activities from Activities link on Home page. when i am checking activities on Account entity its not firing the debugger to check.
Any help from you.. RetrieveMultiple will trigger from any entity right while viewing activities.
Hello Guru Prasad,
ReplyDeleteFor some entities like Account and Contact Rollup message is triggered. Sample you can check here - http://a33ik.blogspot.com/2010/01/handling-rollup-message-with-plugins-in.html
Hi Andriy,
ReplyDeleteThanks for your response.. The solution which you have provided is an unsupported one. Is there any supported solution to implement activities Roll-up functionality for custom entities?
BTW,I am using CRM 2011 online version, we can't perform unsupported customization's on it..
Any thoughts on CRM Online? also we have multiple child entities.
ReplyDeleteHello David,
DeleteWorkaround provided in article works with webcontext that is unavailable in SandBox plugins. So I believe it could be complicated to do that. Possible workaround is development of custom webresource using html+js or SilverLight.
Hi Andrii,
ReplyDeleteGreat plugin and works nicely with CRM 2011!
Big thanks
Hi danisti,
DeleteI have same requirement to view child entity activities in parent entity in ms crm 2011. I referred andrii's ms crm 4.0 plugin but stuck with converting it ms crm 2011.So can you please provide the ms crm 2011 plugin to fix this issue.This is my id -> kpshetty85@gmail.com
Thanks in Advance.
Hello Andrii
ReplyDeleteGreat work !! - I have modified and developed your plugin for CRM 2011.
I have a question about the prefiltering view in the account entity.
The new_activity lookup Activity Data is now only shown in the Related View and not in the linked associated view.
It is possible to show the activity in the linked associated view and not in the Related View.
--> This means in the same view as Opportunity Activities - or Contact Activities
Regards,
Andreas
Hello Andreas!
DeleteNot sure what do you mean under Related and Linked Associated view...
Kind regards,
Andrii.
Sorry I mean the
Deletefilter:
RollupRelatedByParty (all activities from i.e. the account and the child entities like Contact)
and
RetrieveByParty (only Activitities which are directly linked (related) to the account.
With the modified Plugin the activities of my custom child entity with own activities are only shon in the RetrieveByParty view.
I have seen that you posted are unsupported SQL Statement for enabling SDK Message Rollup.
Is this perhaps a possible way to show the activitities of the custom entity in the RollupRelatedByParty View?
Do you have some experiences with this "dirty" change?
-->http://a33ik.blogspot.com/2010/01/handling-rollup-message-with-plugins-in.html
Regards,
Andreas