Dynamics 365插件创建关联实体记录报字典键不存在错误求解
问题场景
涉及两个Dataverse实体:
MemberTransaction:会员交易主表MemberTransactionDetail:会员交易明细表
业务要求:新建MemberTransaction记录时,自动同步创建一条关联的MemberTransactionDetail记录。
实体字段定义
MemberTransaction 字段
MemberTransactionId PK, MemberTransactionNo String, TransactionDate DateTime, MemberId LookUp
MemberTransactionDetail 字段
MemberTransactionDetailId PK, MemberTransactionId LookUp, ProductId LookUp, Qty number
原有实现代码
public void Execute(IServiceProvider serviceProvider) { try { var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); var postImage = context.PostEntityImages["PostImage"]; var entity = (Entity)context.InputParameters["Target"]; if (entity.Attributes.Contains("KEY")) { var memberTransactionId = postImage.GetAttributeValue<Guid>("trn_membertransactionid"); var memberTransactionNo = postImage.GetAttributeValue<String>("trn_membertransactionno"); var transactionDetail = new Entity("trn_membertransactiondetail"); transactionDetail["trn_membertransactionno"] = memberTransactionNo; transactionDetail["trn_membertransactionid"] = new EntityReference("trn_membertransactiondetail", memberTransactionId); transactionDetail["trn_transactiondetailno"] = "6667"; var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); var service = serviceFactory.CreateOrganizationService(context.UserId); var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); tracingService.Trace("Plugin: Creating the Transaction Detail."); service.Create(transactionDetail); var transactionDetailId = transactionDetail.Id; tracingService.Trace("The Detail Id is " + transactionDetailId); } } catch (Exception ex) { Console.Write("What?" + ex.Message); } }
报错信息
插件运行时抛出异常:The given key was not present in the dictionary.
排查与修复方案
该错误是字典键值匹配失败导致,按以下优先级定位修复即可:
- PostImage 注册缺失/别名不匹配(最高概率诱因)
代码在进入逻辑判断前就执行了context.PostEntityImages["PostImage"]取值,只要插件步骤没有注册别名严格为PostImage的Post-operation实体镜像,这行代码会直接抛出键不存在错误。
修复方式:- 打开插件注册工具,找到绑定
MemberTransaction实体Create消息的插件步骤 - 注册后期镜像,别名设为
PostImage,将代码用到的trn_membertransactionid、trn_membertransactionno字段加入镜像字段列表 - 更简单的方案:Create消息触发时,InputParameters里的Target实体本身就携带新建记录的主键ID,完全不需要依赖PostImage,直接用
entity.Id就能获取主记录ID,可省去镜像注册步骤。
- 打开插件注册工具,找到绑定
- 无效硬编码判断导致逻辑不执行
代码中if (entity.Attributes.Contains("KEY"))是无效判断,KEY是无意义硬编码字符串,主实体属性集合中不可能存在该键,即使PostImage配置正确,内部创建明细的逻辑块也永远不会执行。
修复方式:直接删除该无效判断,或替换为实际需要的业务校验逻辑(比如判断必填字段不为空)。 - 查找字段EntityReference配置错误
给明细表关联主表的查找字段赋值时,new EntityReference("trn_membertransactiondetail", memberTransactionId)的实体名写反,指向了明细表自身而非主表,即使前面逻辑正常,执行Create操作时也会触发关联字段校验错误。
修复方式:将实体名修正为主表逻辑名:transactionDetail["trn_membertransactionid"] = new EntityReference("trn_membertransaction", memberTransactionId); - 异常捕获逻辑失效
现有catch块用Console.Write输出错误完全无效,插件运行无控制台上下文,异常会被吞掉无法定位具体出错行。
修复方式:用追踪服务记录完整错误栈,再将异常抛给平台展示:catch (Exception ex) { tracingService.Trace("Plugin error: {0}", ex.ToString()); throw new InvalidPluginExecutionException("自动创建交易明细失败", ex); }
额外注意:插件步骤需要注册在Post-operation阶段、同步执行模式,避免主记录未完成持久化时创建明细导致关联失败。
修正后核心可运行代码
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); var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); try { Entity target = (Entity)context.InputParameters["Target"]; // 直接从Target取新建主记录的ID,无需PostImage Guid mainRecordId = target.Id; string transactionNo = target.GetAttributeValue<string>("trn_membertransactionno"); Entity detail = new Entity("trn_membertransactiondetail"); // 关联主记录,注意实体名不要写错 detail["trn_membertransactionid"] = new EntityReference("trn_membertransaction", mainRecordId); // 明细表存在对应字段再赋值,否则删除该行 // detail["trn_membertransactionno"] = transactionNo; detail["trn_transactiondetailno"] = "6667"; tracingService.Trace("Start creating transaction detail for main record: " + mainRecordId); Guid detailId = service.Create(detail); tracingService.Trace("Transaction detail created, ID: " + detailId); } catch (Exception ex) { tracingService.Trace("Full error stack: " + ex.ToString()); throw new InvalidPluginExecutionException("交易明细创建失败:" + ex.Message, ex); } }
内容的提问来源于stack exchange,提问作者Haminteu
相关产品推荐
相关产品推荐

