Dataverse早期绑定实体中EntityReference的作用及关联实体查询咨询
问题解答
除了你提到的两种处理方式,还有以下几种可行的优化或替代方案:
1. 用FetchXML查询+自定义扩展方法简化取值
FetchXML是Dataverse原生支持的查询语言,定义关联实体字段的语法更直观,查询结果同样返回AliasedValue,但可以封装扩展方法来简化取值逻辑,避免重复的类型转换代码。
示例FetchXML:
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false"> <entity name="incident"> <attribute name="casetypecode" /> <attribute name="contactid" /> <attribute name="createdon" /> <attribute name="incidentid" /> <attribute name="modifiedon" /> <attribute name="prioritycode" /> <attribute name="statuscode" /> <attribute name="title" /> <link-entity name="myentity" from="myentityid" to="myentityid" alias="myEntity" link-type="outer"> <attribute name="field1" /> <attribute name="field2" /> </link-entity> </entity> </fetch>
执行查询并使用扩展方法取值:
// 执行FetchXML查询 var fetchXml = @"上述XML内容"; var result = _service.RetrieveMultiple(new FetchExpression(fetchXml)); var incidents = result.Entities.Select(e => e.ToEntity<Incident>()); // 封装扩展方法简化AliasedValue转换 public static T GetAliasedValue<T>(this Entity entity, string aliasField) { if (entity.Attributes.TryGetValue(aliasField, out var value) && value is AliasedValue aliased) { return (T)aliased.Value; } return default; } // 映射DTO时的简化代码 var dto = new IncidentDto() { Title = incidentEntity.Title, // ...其他字段 MyEntity = incidentEntity.MyEntity != null ? new MyEntity() { Field1 = incidentEntity.GetAliasedValue<string>("myEntity.field1"), Field2 = incidentEntity.GetAliasedValue<string>("myEntity.field2") } : null };
2. 用AutoMapper实现自动映射
可以借助AutoMapper这类对象映射库,提前配置好Entity到DTO的映射规则,自动处理AliasedValue到关联实体字段的转换,省去手动赋值的繁琐。
示例配置与使用:
// 配置AutoMapper映射规则 var mapperConfig = new MapperConfiguration(cfg => { cfg.CreateMap<Incident, IncidentDto>() .ForMember(dest => dest.MyEntity, opt => opt.MapFrom(src => src.MyEntity != null ? new MyEntity { Field1 = src.GetAliasedValue<string>("myEntity.field1"), Field2 = src.GetAliasedValue<string>("myEntity.field2") } : null)) .ForAllMembers(opt => opt.Condition((src, dest, srcMember) => srcMember != null)); }); // 创建映射器并转换 var mapper = mapperConfig.CreateMapper(); var dtos = incidents.Select(mapper.Map<IncidentDto>);
3. 批量查询关联实体(优化单独Retrieve的性能)
如果选择单独获取关联实体的方式,不要逐个调用Retrieve,而是先收集所有需要查询的关联实体ID,再用QueryExpression批量查询,避免N+1查询的性能问题。
示例代码:
// 先获取主实体列表 var incidents = _service.RetrieveMultiple(query)?.Entities?.Select(e => e.ToEntity<Incident>()).ToList(); // 收集所有非空的关联实体ID var myEntityIds = incidents.Where(i => i.MyEntity != null).Select(i => i.MyEntity.Id).ToList(); if (myEntityIds.Any()) { // 批量查询关联实体 var myEntityQuery = new QueryExpression(MyEntity.EntityLogicalName) { ColumnSet = new ColumnSet("myentityid", "field1", "field2"), Criteria = new FilterExpression { Conditions = { new ConditionExpression("myentityid", ConditionOperator.In, myEntityIds.ToArray()) } } }; var myEntities = _service.RetrieveMultiple(myEntityQuery).Entities.Select(e => e.ToEntity<MyEntity>()).ToDictionary(e => e.MyEntityId.Id); // 关联到主DTO foreach (var incident in incidents) { var dto = new IncidentDto { Title = incident.Title /* ...其他字段 */ }; if (incident.MyEntity != null && myEntities.TryGetValue(incident.MyEntity.Id, out var myEntity)) { dto.MyEntity = myEntity; } } }
补充说明
你提到的两种方法是Dataverse查询关联数据的基础方案,上面的方案都是基于这些基础逻辑的优化,核心还是处理Dataverse返回的关联数据格式。需要根据你的业务场景选择:
- 追求代码简洁性:用FetchXML+扩展方法或AutoMapper
- 追求性能:优先选择批量查询关联实体,避免逐个
Retrieve
内容的提问来源于stack exchange,提问作者FEST
相关产品推荐
相关产品推荐

