如何使用Dynamics 365 XRM Tooling SDK通过主要ID通常获取枚举的实体记录集

时间:2019-01-23 22:15:56

标签: c# dynamics-crm fetchxml dynamics-crm-365

我正在尝试编写一种通用方法,该方法给定任何Dynamics 365实体名称,并且一组ID(GUIDS)将以与该枚举集匹配的一组实体记录进行响应。我感到沮丧的是,似乎没有一种有效的方法来使API能够简单地使用“主ID密钥”而不先从元数据中获取它,这是另一次(看似不必要的)往返。

请考虑以下(破解)方法:

    public EntityCollection HackedFetchEntityRecordsById(IOrganizationService orgSvc, string entityName, IEnumerable<Guid> primaryEntityAttributeIds)
    {
        // Defacto HACK for getting primary entity attribute
        string primaryEntityAttribute = $"{entityName}id";

        StringBuilder sb = new StringBuilder();

        foreach (Guid guid in primaryEntityAttributeIds)
        {
            sb.AppendLine($@"<value>{guid}</value>");
        }

        string fetchXml = $@"
                    <fetch mapping='logical'>
                        <entity name='{entityName}'>
                            <no-attrs />
                            <filter>
                                <condition attribute='{primaryEntityAttribute}' operator='in'>
                                    {sb}
                                </condition>
                            </filter>
                        </entity>
                    </fetch> ";

        return orgSvc.RetrieveMultiple(new FetchExpression(fetchXml));
    }

请注意,这里我只是使用观察到的事实上的标准,因为微软似乎选择使用实体名称后跟字符串“ id”来命名实体上的主要id属性。这显然是不安全的,也是一种糟糕的方法。

我可以以“正确”的方式做到这一点,但是效率低下:

    public EntityCollection InefficientFetchEntityRecordsById(IOrganizationService orgSvc, string entityName, IEnumerable<Guid> primaryEntityAttributeIds)
    {
        // "Correct" but inefficient way of getting primary entity attribute
        string primaryEntityAttribute = ((RetrieveEntityResponse) orgSvc.Execute(new RetrieveEntityRequest
        {
            LogicalName = entityName
        })).EntityMetadata.PrimaryIdAttribute;

        StringBuilder sb = new StringBuilder();

        foreach (Guid guid in primaryEntityAttributeIds)
        {
            sb.AppendLine($@"<value>{guid}</value>");
        }

        string fetchXml = $@"
                    <fetch mapping='logical'>
                        <entity name='{entityName}'>
                            <no-attrs />
                            <filter>
                                <condition attribute='{primaryEntityAttribute}' operator='in'>
                                    {sb}
                                </condition>
                            </filter>
                        </entity>
                    </fetch> ";

        return orgSvc.RetrieveMultiple(new FetchExpression(fetchXml));
    }

请注意,在这种情况下,我需要进行单独的服务调用(包括所有开销)以获取实体元数据,以便辨别主要属性是什么。好吧。

我想做类似下面的方法(幻想/不起作用):

    public EntityCollection FantasyFetchEntityRecordsById(IOrganizationService orgSvc, string entityName, IEnumerable<Guid> primaryEntityAttributeIds)
    {
        StringBuilder sb = new StringBuilder();

        foreach (Guid guid in primaryEntityAttributeIds)
        {
            sb.AppendLine($@"<value>{guid}</value>");
        }

        // ILLEGAL XML - made up element "primaryEntityAttribute"
        string fetchXml = $@"
                    <fetch mapping='logical'>
                        <entity name='{entityName}'>
                            <no-attrs />
                            <filter>
                                <primaryEntityAttribute operator='in'>
                                    {sb}
                                </primaryEntityAttribute>
                            </filter>
                        </entity>
                    </fetch> ";

        return orgSvc.RetrieveMultiple(new FetchExpression(fetchXml));
    }

我很高兴在RetrieveMultiple服务中使用QueryBase的其他实现。

2 个答案:

答案 0 :(得分:1)

由于“ hacked”方法在大多数情况下都可以工作,因此也许可以通过在实体名称后附加id来尝试“ hacked”方法。如果失败,则检索实体元数据以获取primaryId。

答案 1 :(得分:0)

创建实体时,主键由CRM设置,并且遵循“实体名称” +“ id”,following this format isn't a hack的格式。

如果您对此不满意,我将使用元数据服务一次批量检索详细信息。

RetrieveAllEntitiesRequest request = new RetrieveAllEntitiesRequest()
{
    EntityFilters = EntityFilters.Entity,
    RetrieveAsIfPublished = true
};

RetrieveAllEntitiesResponse response = (RetrieveAllEntitiesResponse)_serviceProxy.Execute(request);

foreach (EntityMetadata currentEntity in response.EntityMetadata)
{
    currentEntity.PrimaryIdAttribute
}

我不确定这样做有什么问题,大概是您为每个实体进行了多次服务调用,一个额外的元数据调用不会受到影响。至于期望服务器“只知道”此信息;仍然可能必须查询元数据表。

最后,如果有人必须向您提供实体名称,您也可以要求提供主键字段。