C# 使用FetchXML获取(强类型)相关实体

C# 使用FetchXML获取(强类型)相关实体,c#,dynamics-crm-2011,dynamics-crm,C#,Dynamics Crm 2011,Dynamics Crm,我正在使用fetchXML连接两个实体,并且只能获得第一个列表的结果。我可能犯了一个愚蠢的错误,但这让我胡闹了好几个小时 var query = @" <fetch version='1.0' mapping='logical' distinct='true'> <entity name='contact'> <all-attributes /> <link-entity name='new_custom' from='new_c

我正在使用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);
var query=@”
";
var fe=新的FetchExpression(查询);
var结果=服务。检索多个(fe);
//此联系人实体已正确填写
var contact=result.Entities.First().Cast();
//此关系为空,这是意外的!
var custom=contact.new\u contact\u new\u custom;
//也为null(不确定这是否有效)
var related=contact.GetRelatedEntity(“新联系人新自定义”,null);

我确实看到在联系人实体的
属性
格式化值
属性中检索到了正确的数据。但为什么这种关系没有建立正确呢?如何将此数据转换为正确的“自定义”实体类型?

首先:您确定查询返回早期绑定的对象吗?在我下面的示例中,我假设您得到了实体对象(后期绑定),但对于这个示例来说,这并没有多大区别

查询的响应基本上是请求类型的实体对象的普通表,在本例中为“contact”。连接实体的字段也可以添加到此表中,但它们被包装在
AliasedValue
对象中。它们的列名以
LinkEntity
别名作为前缀,以防止名称冲突

您的行
var contact=result.Entities.Cast()
表明变量
contact
属于
contact
类型,但实际上它是一个
IEnumerable
。(使用
var
并不总是那么有用。)因此,我怀疑您的最后两行代码甚至无法编译

在下面的示例中,将向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;
var fetchXml=@”
";
var query=新的FetchExpression(fetchXml);
var response=service.RetrieveMultiple(查询);
var contact=response.Entities[0];
var customField=contact.GetAttributeValue(“nc.new_name”);
字符串名称=自定义字段!=无效的(字符串)customField.Value:空;

这是一个有点晚的答案,但这个问题帮助我走上了正确的轨道,所以我想我应该添加我的文章。正如Henk在对其答案的评论中所说,您可以实现一个相对简单的扩展方法,将链接实体的字段解析为另一个实体,然后将其转换为早期绑定类型。您只需要知道用于
链接实体
元素的别名。以下是我的实现(编辑:添加FormattedValues):

publicstatict-to-latedentity(此实体为rawEntity,字符串相关别名)
其中T:CrmEntity,new()
//CrmEntity是我插入到生成代码中的基类
//区分早期绑定类;您可以使用实体
{
var结果=新实体(新T().LogicalName);
foreach(rawEntity.Attributes中的var属性
.Where(kvp=>kvp.Key
.StartsWith(relatedAlias+“))
{
var newName=attribute.Key.Replace(relatedAlias+”,String.Empty);
结果[新名称]=((AliasedValue)属性.Value).Value;
}
foreach(rawEntity.FormattedValues中的var formattedValue
.Where(kvp=>kvp.Key
.StartsWith(relatedAlias+“))
{
var newName=formattedValue.Key.Replace(relatedAlias+”,String.Empty);
result.FormattedValues[newName]=formattedValue.Value;
}
返回结果.ToEntity();
}
//用法
var query=新的FetchExpression(fetchXml);
var response=service.RetrieveMultiple(查询);
var contact=response.Entities[0].ToEntity();
var newCustom=response.Entities[0].ToRelatedEntity(“nc”);

非常基本,但只要您没有对正在检索的任何字段使用别名,并且检索到足够的信息来填充对象的有效实例(Id、主字段等),它似乎工作得很好。这比尝试用初始值设定项实例化相关对象要好得多(特别是因为像
StateCode
这样的许多字段都是只读的)。

对于这个不太有趣的示例,很抱歉,修复了它。所以只能从链接实体中获取属性?我想获取绑定实体对象(不发送两个查询)。回答第一个问题:是的,我使用的是早期绑定实体。另外,从Contact到new_custom的关系是1:M。我认为您无法轻松地从FetchXml查询中获取链接的实体对象。恐怕您必须开发一些帮助程序代码才能使其正常工作。
    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");