我正在使用fetchXML来连接两个实体,并且只能获得第一个列表的结果。我可能犯了一个愚蠢的错误,但这让我几个小时不知所措。
var query = @"
<fetch version='1.0' mapping='logical' distinct='true'>
<entity name='contact'>
<all-attributes />
<link-entity name='new_custom' from='new_contactid' to='contactid' link-type='inner'>
<all-attributes />
</link-entity>
</entity>
</fetch>
";
var fe = new FetchExpression(query);
var result = service.RetrieveMultiple(fe);
// This contact entity is properly filled
var contact = result.Entities.First().Cast<Contact>();
// This relationship is null, that's unexpected!
var custom = contact.new_contact_new_custom;
// Also null (not sure if this should work)
var related = contact.GetRelatedEntity<new_custom>("new_contact_new_custom", null);
我确实看到在Contact实体的Attributes
和FormattedValues
属性中检索到了正确的数据。但为什么关系设置不正确呢?如何将此数据转换为正确的“自定义”实体类型?
答案 0 :(得分:3)
首先:你确定你的查询返回早期绑定的对象吗?在我下面的例子中,我假设你得到了实体对象(后期绑定),但是对于这个例子,它实际上并没有太大的区别。
查询的响应基本上是您请求的类型的实体对象的普通表,在本例中为“contact”。已连接实体的字段也可以添加到此表中,但它们包含在AliasedValue
个对象中。它们的列名以LinkEntity
别名作为前缀,以防止名称冲突。
您的行var contact = result.Entities.Cast<Contact>();
表示变量contact
的类型为Contact
,但实际上是IEnumerable<Contact>
。 (使用var
并不总是那么有用。)因此我怀疑你的最后两行甚至没有编译。
在下面的示例中,fetch-query被发送到Organization.svc端点。 (注意别名属性。)然后,实体“new_custom”的字段“new_name”取自查询结果集的第一行。
var fetchXml = @"
<fetch version='1.0' mapping='logical' distinct='true'>
<entity name='contact'>
<all-attributes />
<link-entity name='new_custom' alias='nc' from='new_contactid' to='contactid' link-type='inner'>
<all-attributes />
</link-entity>
</entity>
</fetch>
";
var query = new FetchExpression(fetchXml);
var response = service.RetrieveMultiple(query);
var contact = response.Entities[0];
var customField = contact.GetAttributeValue<AliasedValue>("nc.new_name");
string name = customField != null ? (string)customField.Value : null;
答案 1 :(得分:3)
这是一个迟到的答案,但这个问题帮助我走上正轨,所以我想我会加入我的作品。就像Henk在对他的回答的评论中所说,你可以实现一个相对简单的扩展方法来将链接实体的字段解析成另一个实体,然后将其转换为早期绑定类型。您需要知道的是用于link-entity
元素的别名。这是我的实现(编辑:添加了FormattedValues):
public static T ToRelatedEntity<T>(this Entity rawEntity, string relatedAlias)
where T:CrmEntity, new()
//CrmEntity is a base class I insert into my generated code
//to differentiate early-bound classes; you can use Entity
{
var result = new Entity(new T().LogicalName);
foreach(var attribute in rawEntity.Attributes
.Where(kvp=>kvp.Key
.StartsWith(relatedAlias + ".")))
{
var newName = attribute.Key.Replace(relatedAlias + ".", String.Empty);
result[newName] = ((AliasedValue)attribute.Value).Value;
}
foreach(var formattedValue in rawEntity.FormattedValues
.Where(kvp=>kvp.Key
.StartsWith(relatedAlias + ".")))
{
var newName = formattedValue.Key.Replace(relatedAlias + ".", String.Empty);
result.FormattedValues[newName] = formattedValue.Value;
}
return result.ToEntity<T>();
}
//usage
var query = new FetchExpression(fetchXml);
var response = service.RetrieveMultiple(query);
var contact = response.Entities[0].ToEntity<Contact>();
var newCustom = response.Entities[0].ToRelatedEntity<new_custom>("nc");
非常基本,但只要您不对任何您正在检索的字段别名,并且您正在检索足够的信息来填充有效的实例,它似乎工作得很好。对象(Id,主要字段等)。它比尝试使用初始化程序实例化相关对象要好得多(特别是因为许多字段如StateCode
是只读的)。