This solution efficiently copies or clones Microsoft Dynamics 365 CRM records and their child records, eliminating the need for repetitive data entry by transferring existing data from one entity to another.
Introduction
I need to clone/copy the records of the dynamic CRM entity and all its related child records. I can clone the primary entity easily by adding relationships and mapping the source entity's fields with the target entity's fields. Still, the challenge was copying/cloning its child records and linking them.
Background
You need to be aware of Dynamic CRM plugin or custom workflow development (Code Activity).
To copy or clone child records from one entity to another in Dynamics 365 CRM; you will typically need to use custom code to automate the process. The process involves querying the child records related to a specific record in one entity, creating new records in the target entity, and establishing the relationships between them.
The problem is mapping all the fields individually, which is quite hectic. Suppose there are 100 fields in the associated entity record, and you want to clone all the fields from the related entity. Then, you will only end up writing 100 lines. Also, you must update the plugin code whenever you add new fields.
I tried to eliminate writing code for every field mapping and found a tricky solution in MeghShyam Gaur's post here. The main trick is to remove the primary key of the retrieved associated record and set the primary key value to Guid.NewGuid()
, and finally, remove the parent record ID of the retrieved associated record.
Using the code
- Clone the primary entity
public static Entity CloneEntitySandbox(Entity entityToClone)
{
var newEntity = new Entity(entityToClone.LogicalName);
var systemAttributes = new List<string>();
systemAttributes.Add("createdon");
systemAttributes.Add("createdby");
systemAttributes.Add("modifiedon");
systemAttributes.Add("modifiedby");
systemAttributes.Add("owninguser");
systemAttributes.Add("owningbusinessunit");
foreach (var attribute in entityToClone.Attributes
.Where(x => x.Key != entityToClone.LogicalName + "id")
.Where(x => !systemAttributes.Contains(x.Key)))
{
switch (attribute.Value.GetType().Name)
{
case "Money":
var m = attribute.Value as Money;
newEntity[attribute.Key] = new Money(m.Value);
break;
case "EntityReference":
var er = attribute.Value as EntityReference;
newEntity[attribute.Key] = new EntityReference(er.LogicalName, er.Id);
break;
case "OptionSetValue":
var os = attribute.Value as OptionSetValue;
newEntity[attribute.Key] = new OptionSetValue(os.Value);
break;
default:
newEntity[attribute.Key] = attribute.Value;
break;
}
}
return newEntity;
}
- Identify Source and Target Child Entities:
Determine the source entityId
(where the child records exist) and the target entityId
(where you want to copy the child records).
CloneEntityassociatedRecordsToAnother(orgService, sourceEntityId, targetEntityId,"parentcustomerid","contact", "contactid");
- Query the Child Records
The following steps are to create the clone of child records from one entity to another. Assuming you are using a plugin or custom workflow.
public void CloneEntityassociatedRecordsToAnother(IOrganizationService organizationService,Guid sourceEntityId, Guid targetEntityId, string strForignKeyAttributeName, string strDetailEentityLogicalName, string strDetailEntityPrimaryKeyName)
{
try
{
QueryExpression query = new QueryExpression{ EntityName = strDetailEentityLogicalName, ColumnSet = new ColumnSet(true),
Criteria = {FilterOperator = LogicalOperator.And, Conditions = {
new ConditionExpression {
AttributeName = strForignKeyAttributeName,
Operator = ConditionOperator.Equal,
Values = { sourceEntityId.ToString()}}
}}
};
foreach (Entity retrieve in organizationService.RetrieveMultiple(query).Entities)
{
retrieve.Attributes.Remove(strDetailEntityPrimaryKeyName);
retrieve.Id = Guid.NewGuid();
retrieve.Attributes.Remove(strForignKeyAttributeName);
EntityReference newContractId = SetRefrence(strDetailEentityLogicalName, targetEntityId);
retrieve.Attributes.Add(strForignKeyAttributeName, newContractId);
organizationService.Create(retrieve);
}
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException("Clone Entityassociated Records To Another Plugin: " + ex.Message);
}
}
-
Establish a relationship between the newly created records and the target entity.
public static EntityReference SetRefrence(string Ent, Guid entRef)
{
EntityReference r_EntRef = null;
if (entRef != null) r_EntRef = new EntityReference(Ent, entRef);
return r_EntRef;
}
Points of Interest
- Error Handling: Implement proper error handling to manage any issues arising during copying.
- Testing: Thoroughly test your solution in a development environment before deploying it to production.
References
Keep a running update of any changes or improvements you've made here.