如何在Dynamics CRM VOC中通过C#关联调查问题与响应路由?
解决Dynamics CRM响应路由与问题的关联问题
嘿,我来帮你理清楚怎么在C#代码里关联响应路由(ResponseRouting)和对应的问题。在Dynamics 365 Customer Voice(也就是你说的Dynamics CRM调查模块)里,msdyn_responserouting实体其实自带了两个关键的Lookup属性,专门用来关联问题,只是你可能没注意到它们:
msdyn_question: 这个字段指向该响应路由监听的触发问题——也就是触发路由规则的那个问题msdyn_targetquestion: 这个字段指向该路由规则管理的目标问题——也就是路由规则控制显示/隐藏的问题
接下来我会基于你的现有代码,给出具体的关联实现方案。
1. 先修正响应路由的查询逻辑
首先,我建议你明确指定要获取的字段(当然继续用ColumnSet(true)全量获取也可以,但指定字段更高效),确保拿到这两个关联字段:
private static DataCollection<Entity> GetRouting(Guid _surveyId) { QueryExpression routingQuery = new QueryExpression { EntityName = "msdyn_responserouting", // 这里假设你的query参数传入的是这个标准实体名,如果有自定义实体请替换 ColumnSet = new ColumnSet("msdyn_name", "msdyn_question", "msdyn_targetquestion", "msdyn_routingtype"), Criteria = new FilterExpression { Conditions = { new ConditionExpression { AttributeName = "msdyn_survey", Operator = ConditionOperator.Equal, Values = {_surveyId} } } } }; return connection.service.RetrieveMultiple(routingQuery).Entities; }
2. 关联问题与响应路由的核心代码
拿到问题集合和路由集合后,我们可以用字典做快速映射,然后遍历路由关联对应的问题:
// 先获取所有问题,并构建ID到实体的字典,方便快速查找 var surveyQuestions = GetQuestions(yourSurveyId); var questionLookup = surveyQuestions.ToDictionary(q => q.Id, q => q); // 获取所有响应路由 var responseRoutings = GetRouting(yourSurveyId); // 遍历每个路由,关联触发问题和目标问题 foreach (var routing in responseRoutings) { // 处理监听的触发问题 var triggerQuestionRef = routing.GetAttributeValue<EntityReference>("msdyn_question"); if (triggerQuestionRef != null && questionLookup.TryGetValue(triggerQuestionRef.Id, out var triggerQuestion)) { // 这里可以把关联结果存入你的自定义模型,或者直接使用 Console.WriteLine($"路由「{routing["msdyn_name"]}」监听的问题:{triggerQuestion["msdyn_name"]}"); } // 处理管理的目标问题 var targetQuestionRef = routing.GetAttributeValue<EntityReference>("msdyn_targetquestion"); if (targetQuestionRef != null && questionLookup.TryGetValue(targetQuestionRef.Id, out var targetQuestion)) { Console.WriteLine($"路由「{routing["msdyn_name"]}」管理的问题:{targetQuestion["msdyn_name"]}"); } }
3. (可选)更高效的关联查询:用LinkEntity一次获取所有数据
如果你想减少API调用次数,可以使用LinkEntity在一个查询里同时拉取路由和关联的问题数据:
private static DataCollection<Entity> GetRoutingWithLinkedQuestions(Guid _surveyId) { QueryExpression routingQuery = new QueryExpression { EntityName = "msdyn_responserouting", ColumnSet = new ColumnSet("msdyn_name", "msdyn_routingtype"), Criteria = new FilterExpression { Conditions = { new ConditionExpression { AttributeName = "msdyn_survey", Operator = ConditionOperator.Equal, Values = {_surveyId} } } }, // 关联触发问题 LinkEntities = { new LinkEntity { LinkFromEntityName = "msdyn_responserouting", LinkFromAttributeName = "msdyn_question", LinkToEntityName = "msdyn_question", LinkToAttributeName = "msdyn_questionid", Columns = new ColumnSet("msdyn_name", "msdyn_text"), EntityAlias = "TriggerQuestion" }, // 关联目标问题 new LinkEntity { LinkFromEntityName = "msdyn_responserouting", LinkFromAttributeName = "msdyn_targetquestion", LinkToEntityName = "msdyn_question", LinkToAttributeName = "msdyn_questionid", Columns = new ColumnSet("msdyn_name", "msdyn_text"), EntityAlias = "TargetQuestion" } } }; return connection.service.RetrieveMultiple(routingQuery).Entities; }
使用这个查询的话,直接从返回结果里拿关联数据即可:
var routedQuestions = GetRoutingWithLinkedQuestions(yourSurveyId); foreach (var routing in routedQuestions) { var triggerQuestionName = routing.GetAttributeValue<AliasedValue>("TriggerQuestion.msdyn_name")?.Value.ToString(); var targetQuestionName = routing.GetAttributeValue<AliasedValue>("TargetQuestion.msdyn_name")?.Value.ToString(); Console.WriteLine($"路由「{routing["msdyn_name"]}」:监听【{triggerQuestionName}】,管理【{targetQuestionName}】"); }
注意事项
- 确认你的Dynamics环境里
msdyn_responserouting实体的字段名称和我说的一致,不同版本的Customer Voice可能略有调整,但核心的关联逻辑是统一的。 - 如果你的
GetRouting方法里的query参数是用来区分不同类型的路由实体,记得替换成对应的实体名称即可。
内容的提问来源于stack exchange,提问作者Headhunter Xamd
相关产品推荐
相关产品推荐

