Dataverse插件Update消息报错:给定的键不在字典中
问题原因
Dataverse插件触发Update消息时,默认传入的entity对象仅包含本次被修改的字段,而非完整实体。如果本次更新未改动stagingtype字段,直接通过entity["stagingtype"]取值就会触发「键不存在」的错误。而Create消息时传入的是完整实体,所以不会有这个问题。
另外原代码还有个隐藏问题:Update时查询重复会把当前记录本身算进去,导致误判重复。
解决方法
推荐直接获取完整实体来避免字段缺失问题,同时修正查询逻辑排除当前记录:
修改后的完整代码
if (entity.LogicalName == "atmtransaction") { tracingService.Trace("Stage {0}", "1"); // 获取当前实体的ID Guid recordId = ((EntityReference)context.InputParameters["Target"]).Id; // 从Dataverse获取完整的实体记录,指定需要的字段 Entity fullEntity = service.Retrieve("atmtransaction", recordId, new ColumnSet("stagingtype", "store", "date")); tracingService.Trace("Stage {0}", "2"); OptionSetValue stagingType = (OptionSetValue)fullEntity["stagingtype"]; tracingService.Trace("Stage {0}", "3"); string store = (string)fullEntity["store"]; tracingService.Trace("Stage {0}", "4"); DateTime date = (DateTime)fullEntity["date"]; tracingService.Trace("Stage {0}", "5"); if (stagingType.Value != 1) { tracingService.Trace("Stage {0}", "6"); // 检查重复:排除当前更新的记录本身 QueryExpression query = new QueryExpression("ada_atmtransaction"); query.Criteria.AddCondition("ada_store", ConditionOperator.Equal, store); query.Criteria.AddCondition("ada_date", ConditionOperator.Equal, date); query.Criteria.AddCondition("ada_atmtransactionid", ConditionOperator.NotEqual, recordId); EntityCollection results = service.RetrieveMultiple(query); if (results.Entities.Count > 0) { tracingService.Trace("Stage {0}", "7"); throw new InvalidPluginExecutionException("A record already exists with the same store and date."); } } }
关键修改点
- 获取完整实体:通过
service.Retrieve指定需要的字段(stagingtype、store、date),确保无论字段是否被修改都能拿到值。 - 排除当前记录:在查询条件中添加
ada_atmtransactionid != 当前记录ID,避免Update时误判自身为重复记录。
备选方案(仅处理单个字段)
如果不想获取完整实体,可以单独检查字段是否存在,不存在则从数据库查询该字段:
OptionSetValue stagingType; Guid recordId = ((EntityReference)context.InputParameters["Target"]).Id; if (entity.Contains("stagingtype")) { stagingType = (OptionSetValue)entity["stagingtype"]; } else { // 仅查询stagingtype字段 Entity existingRecord = service.Retrieve("atmtransaction", recordId, new ColumnSet("stagingtype")); stagingType = (OptionSetValue)existingRecord["stagingtype"]; }
但这种方法需要对每个可能缺失的字段做判断,不如直接获取完整实体简洁可靠。
内容的提问来源于stack exchange,提问作者liam
相关产品推荐
相关产品推荐

