CRM Dynamics 2016:如何限制商机关联笔记仅可附加单个文件?
限制Dynamics CRM 2016商机笔记仅允许单个附件的实现方案
当然可以实现这个需求!针对Dynamics CRM 2016里商机关联笔记的单文件限制,我给你两种常见的实现思路,分别适配不同的场景:
场景1:限制单条笔记只能有一个附件(增强默认行为)
虽然CRM 2016默认每条笔记(Annotation)只能关联一个附件,但你可以通过客户端脚本优化用户体验,比如阻止用户替换已有附件,或者在误操作时给出明确提示:
客户端JavaScript实现步骤
- 进入CRM后台的设置 > 自定义 > 自定义系统,找到**笔记(Annotation)**实体,打开它的主表单。
- 在表单编辑器中添加一个OnSave事件脚本,代码如下:
function validateSingleAttachment(executionContext) { const formContext = executionContext.getFormContext(); const isExistingRecord = formContext.data.entity.getId() !== null; // 仅针对已有附件的笔记,阻止替换附件 if (isExistingRecord) { const originalFileName = formContext.getAttribute("filename").getOriginalValue(); const currentDocumentBody = formContext.getAttribute("documentbody").getValue(); const originalDocumentBody = formContext.getAttribute("documentbody").getOriginalValue(); if (originalFileName && currentDocumentBody && originalDocumentBody !== currentDocumentBody) { executionContext.getEventArgs().preventDefault(); alert("该笔记已有附件,无法替换或添加新附件!"); } } }
- 绑定脚本时记得勾选传递执行上下文,保存并发布表单即可。
场景2:限制整个商机只能关联一个带附件的笔记
如果你的需求是单个商机只能附加一个文件(即只能有一条带附件的笔记),可以选择客户端脚本快速上线,或者用服务器端插件做严格限制(防止绕过客户端操作):
方法A:客户端JavaScript(商机表单)
这种方式适合快速落地,用户操作时实时给出提示:
- 打开商机的主表单,添加OnSave事件脚本:
function validateOpportunitySingleNote(executionContext) { const formContext = executionContext.getFormContext(); const opportunityId = formContext.data.entity.getId().replace(/[{}]/g, ""); // 去除ID的大括号 // 查询当前商机关联的带附件笔记数量 const fetchXml = `<fetch version="1.0" output-format="xml-platform" mapping="logical"> <entity name="annotation"> <filter type="and"> <condition attribute="objectid" operator="eq" value="${opportunityId}" /> <condition attribute="documentbody" operator="not-null" /> </filter> </entity> </fetchXml>`; Xrm.WebApi.retrieveMultipleRecords("annotation", "?fetchXml=" + encodeURIComponent(fetchXml)).then( (result) => { if (result.entities.length > 1) { executionContext.getEventArgs().preventDefault(); alert("该商机只能附加一个文件,请删除多余的笔记后再保存!"); } }, (error) => { console.error("验证出错:", error.message); alert("验证附件数量时出错,请重试!"); } ); }
- 绑定脚本时勾选传递执行上下文,保存发布表单。
方法B:服务器端插件(严格限制,防止绕过)
客户端脚本可以被开发者工具绕过,如果你需要严格管控,建议用C#插件实现:
using Microsoft.Xrm.Sdk; using System; public class RestrictOpportunitySingleNote : IPlugin { public void Execute(IServiceProvider serviceProvider) { // 获取插件上下文和组织服务 var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); var service = serviceFactory.CreateOrganizationService(context.UserId); // 仅处理笔记实体的创建/更新操作 if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity annotation) { // 检查笔记是否关联商机 if (annotation.Contains("objectid") && annotation["objectid"] is EntityReference objRef && objRef.LogicalName == "opportunity") { var opportunityId = objRef.Id; // 查询商机关联的带附件笔记总数 var fetchXml = $@"<fetch version='1.0' aggregate='true'> <entity name='annotation'> <attribute name='annotationid' alias='note_count' aggregate='count' /> <filter type='and'> <condition attribute='objectid' operator='eq' value='{opportunityId}' /> <condition attribute='documentbody' operator='not-null' /> </filter> </entity> </fetchXml>"; var results = service.RetrieveMultiple(new FetchExpression(fetchXml)); if (results.Entities.Count > 0) { var noteCount = (int)((AliasedValue)results.Entities[0]["note_count"]).Value; // 创建操作:如果已有1条及以上带附件笔记,阻止创建 // 更新操作:如果已有多条,且当前操作不是修改已有的那条,阻止更新 bool isCreate = context.MessageName.Equals("Create", StringComparison.OrdinalIgnoreCase); bool isUpdate = context.MessageName.Equals("Update", StringComparison.OrdinalIgnoreCase); bool exceedsLimit = (isCreate && noteCount >= 1) || (isUpdate && noteCount > 1 && annotation.Id != ((EntityReference)context.PreEntityImages["PreImage"]).Id); if (exceedsLimit) { throw new InvalidPluginExecutionException("该商机只能附加一个文件,无法添加或修改更多笔记!"); } } } } } }
插件注册注意事项:
- 注册在Annotation实体的Create和Update消息上,执行阶段选择PreValidation;
- 针对Update消息,需要添加PreImage,包含
annotationid字段,确保插件能识别是否是修改已有笔记。
内容的提问来源于stack exchange,提问作者Camilo López
相关产品推荐
相关产品推荐

