Bhoopathi

"Be Somebody Nobody Thought You could Be"

Thursday, March 9

Clone associated records(child records) along with parent record in MS CRM 2011

****************************************************************************
Hi All,
As a very common requirement, I was asked to implement the functionality to clone records in CRM 2011 just to copy the existing record and its associated entity records to the cloned one.

Since it looks very simple to clone a record using 1:N relationship mapping like explained in this blog (https://bhoopathigoudk.blogspot.in/2017/03/clonea-record-in-ms-crm-2011-sometimein.html) but the challenge is to copy the associated child records and link them to the cloned (new) record.

So in this, the basic approach can be write a plugin on Post-Create of the cloned record, in that make a query in associated entity table and iterate through the entity collection and then map all the fields of existing child record to cloned child records.

But here the problem is to map all the fields one by one and which is quite a hectic task. Suppose there are 100 fields in 1st associated entity record,50 odd fields in 2nd associated entity record, and you are asked to clone all the fields from the associated entity then you will only end up writing 100 lines of

entity.attributes.add(“attribute_logical_name1”, “value”)
entity.attributes.add(“attribute_logical_name2”, “value”)… and so on.
Now here I tried to get rid of writing a code for every field mapping and found a tricky way. As there is no method for cloning in crmservice like Create, Execute,Update but yes we can clone the child record with the existing crmservice.Create method (see the below code).

In the below code, they main trick is to remove the Remove the primary key of the retrieved associated record, Set the primary key value to Guid.NewGuid() and finally remove the parent record id of the retrieved associated record.

-----------------------------------------------------------------------------------
public void Execute(IServiceProvider serviceProvider)
{
try
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName == "quote")
{
if (entity.Attributes.Contains("new_parentquoteid") == false)
return;
else
{
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);
EntityReference parentQuoteId = (EntityReference)entity.Attributes[“new_parentquoteid”];
Guid quoteid = new Guid(context.OutputParameters[“id”].ToString());
QueryExpression query = new QueryExpression
{
EntityName = “quotedetail”,
ColumnSet = new ColumnSet(true),
Criteria =
{
FilterOperator = LogicalOperator.And,
Conditions = {
new ConditionExpression
{
AttributeName = “quoteid”,
Operator = ConditionOperator.Equal,
Values = {parentQuoteId.Id.ToString()}
}
}
}
};
//Instead of iterating through all the child records and creating one by one we can also use ExecuteMultiple method
foreach (Entity retrieve in service.RetrieveMultiple(query).Entities)
{
//Remove the primary key of the retrieved associated record
retrieve.Attributes.Remove(“quotedetailid”);
//Set the primary key value to Guid.NewGuid()
retrieve.Id = Guid.NewGuid();
//Remove the parent record id of the retrieved associated record
retrieve.Attributes.Remove(“quoteid”);
EntityReference newQuoteId = SetRefrence(“quotedetail”, quoteid);
retrieve.Attributes.Add(“quoteid”, newQuoteId);
service.Create(retrieve);
}
}
}
}
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException(ex.Message.ToString());
}
}
public static EntityReference SetRefrence(string Ent, Guid entRef)
{
EntityReference r_EntRef = null;
if (entRef != null) r_EntRef = new EntityReference(Ent, entRef);
return r_EntRef;
}
Using this, we can easily clone the child records without using any field mapping.