经常有这样的需求,一个单据上有太多要填写的内容,有时还关联多个子单据,客户不想一个一个地填写,他们想从已有的单据上复制数据,克隆成一条新的记录。本文将介绍如何克隆一条记录,包括它的子单据以生成一条新的记录。
主要用到Microsoft.Xrm.Client.EntityExtensions.Clone方法来克隆数据,以及用OrganizationServiceContext来动态复制子单据的数据。
首先在界面上新加一个Clone的按钮,加一个new_clone的字段;点击按钮时,把new_clone字段设为clone以触发插件,插件里完成数据的复制工作,并再次把new_clone字段设成新数据的id,new_clone的onchange事件会调用Xrm.Utility.openEntityForm("new_marketing_plan", cloneValue);来打开新的数据。
下面看下实现方法:
1. 界面上js:
1: //clone field change event2: function openNewEntity() {3: var clone = Xrm.Page.getAttribute("new_clone");4: var cloneValue = clone.getValue();5: if (cloneValue != "clone" && cloneValue != "") {6: clone.setSubmitMode("always");7: clone.setValue("");8: Xrm.Page.data.entity.save();9: Xrm.Utility.openEntityForm("new_marketing_plan", cloneValue);10: }11: }12:13: //clone button click event14: function clone() {15: var clone = Xrm.Page.getAttribute("new_clone");16: clone.setSubmitMode("always");17: clone.setValue("clone");18: Xrm.Page.data.entity.save();19: }
2. 主单据复制:
1: new_marketing_plan newMP = (new_marketing_plan)Microsoft.Xrm.Client.EntityExtensions.Clone(curEnt, true);2: new_marketing_plan mp = new new_marketing_plan() { Id = newMP.Id };3:4: Guid newMPid = Guid.NewGuid();5: newMP.Attributes.Remove("new_marketing_planid");6: newMP.Attributes.Remove("new_name");7: newMP.new_approval_status = new OptionSetValue(1);8: newMP.new_clone = "";9: newMP.EntityState = null;10: newMP.Id = newMPid;11: adminService.Create(newMP);
3. 子表复制:
我这里有9个子表,所以抽出了一个方法以方便使用, 以后要是子单据有变化,只用改下这里的entNames就行了。
1: string entNames = "new_print_plan,new_radio_plan,new_bill_board,new_tv_plan,new_btl_posm,new_btl_poe_fixed,new_promotion_girls,new_promotion_events,new_digital_plan";2: foreach (string entName in entNames.Split(‘,‘))3: {4: CloneRelatedEntities(adminService, newMPid, entName, "new_marketing_planid", mp);5: }6:7: curEnt["new_clone"] = newMPid.ToString();8: adminService.Update(curEnt);
1: private void CloneRelatedEntities(IOrganizationService adminService, Guid newEntityId, string subEntityName, string filterName, Entity parentEntity)2: {3: try4: {5: using (OrganizationServiceContext svcContext = new OrganizationServiceContext(adminService))6: {7: var ents = svcContext.CreateQuery(subEntityName).Where(e => e[filterName] == parentEntity[filterName]).ToList();8: foreach (var ent in ents)9: {10: var newEnt = Microsoft.Xrm.Client.EntityExtensions.Clone(ent);11: newEnt.Attributes[filterName] = new EntityReference(subEntityName, newEntityId);12: newEnt.Id = Guid.NewGuid();13: newEnt.EntityState = null;14: adminService.Create(newEnt);15: }16: }17: }18: catch (Exception ex)19: {20: throw new InvalidPluginExecutionException(MethodBase.GetCurrentMethod().Name + " " + ex.Message);21: }22: }
4. 注意事项
- 当我完成Unit Test,注册完插件后,报了下面的错:
Could not load file or assembly ‘Microsoft.Xrm.Client, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35‘ or one of its dependencies. The system cannot find the file specified
原来这个Client dll在服务器上是没有的,需要我们手动copy上去。从我们本机的“SDK\Bin”里copy到服务器上的“program files\Microsoft Dynamics CRM\CRMWeb\bin”下即可。
- 再点击Clone按钮,又报了一个错:
This workflow job was canceled because the workflow that started it included an infinite loop. Correct the workflow logic and try again. For information about workflow logic, see Help
原来出现死循环了,解决方法很简单,在插件的开始处加上下面代码就行了:
if (context.Depth > 1)
{
return;
}