【问题标题】:How to generically get enumerated set of entity records by primary id with Dynamics 365 XRM Tooling SDK如何使用 Dynamics 365 XRM Tooling SDK 按主 ID 一般获取枚举的实体记录集
【发布时间】:2019-01-23 22:15:56
【问题描述】:

我正在尝试编写一个通用方法,该方法给定任何 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));
    }

请注意,这里我只是使用我观察到的事实标准,因为似乎 Microsoft 已选择使用实体名称后跟字符串“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 实现。

【问题讨论】:

  • “这显然是不安全的,也是一种糟糕的做法。” - 为什么?
  • 在下面查看我对您提出的答案的回复!谢谢!

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


【解决方案1】:

由于“hacked”方法在绝大多数情况下都应该有效,或许可以先尝试“hacked”方法,方法是在实体名称后附加id。如果失败,则检索实体元数据以获取 primaryId。

【讨论】:

  • 也许——但出于谨慎考虑,我需要说“不”。我正在进行集成,没有什么可以阻止第三方用户(草率地)创建自定义实体(我需要能够处理),理论上这些实体可能具有以模式“entityName + id”命名的属性这实际上不是主要的实体属性。我不能冒这种错误情况的风险。不过还是谢谢。
  • 好点。如果您想推送它,对于开箱即用的实体,您可以放心 'logicalName' + "id" 不会是自定义字段。因此,对于不包含“_”或以“msdyn”开头的实体,被黑的方法通常是安全的。话虽如此,当我遇到类似的问题时,我也很不情愿地得出结论,检索元数据是可行的方法。
  • 太令人沮丧了,因为服务器在执行查询的上下文中当然(或很容易)知道主键。
  • 我认为不可能手动创建具有“entityName + id”格式的字段(D365 在您创建实体时会自动创建它),所以我会说如果您是安全的附加“id”。如果您仍然不想走这条路,我会查询元数据并将其保存在缓存中,以避免每次都进行额外的服务调用。
  • 好点系统设置了主键字段。不过,我们仍然可以创建一个名为“entityName + id”的查找字段。如果有一个名为 new_request 的自定义实体,您为其创建了帐户上的查找,则该查找可以称为 new_requestid。但是,将“id”之前的令牌与实体名称进行比较很容易将其区分为帐户上的查找字段......“被黑”方法的另一点。我也同意缓存元数据会有所帮助。
【解决方案2】:

主键由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
}

我不太确定这样做有什么顾虑,大概您正在为每个实体进行多次服务调用,一个额外的元数据调用不会受到伤害。至于期望服务器“只知道”这些信息;无论如何,它可能必须查询元数据表。

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

【讨论】:

  • 跟随你的链接,这里是措辞:“备注值通常是 + “id”。”这种“通常”的使用听起来确实像是微软在竭尽全力避免做出约定的承诺!可悲的是,我需要依靠这一点。我将查询并缓存元数据。不过谢谢你的想法。
  • 创建新实体时绝对可以更改主名称属性的名称。我之前遇到过这种情况
猜你喜欢
  • 2019-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-01
  • 1970-01-01
相关资源
最近更新 更多