Как в общем случае получить перечислимый набор записей сущностей по первичному идентификатору с помощью Dynamics 365 XRM Tooling SDK - PullRequest
0 голосов
/ 24 января 2019

Я пытаюсь написать общий метод, который с любым именем сущности Dynamics 365 и набором идентификаторов (GUIDS) будет отвечать набором записей сущностей, соответствующих этому перечисляемому набору. Я разочарован тем, что не представляется эффективным способом заставить API просто использовать «первичный ключ идентификатора», не получая его сначала из метаданных, другого (казалось бы, ненужного) приема в оба конца.

Рассмотрим следующий (взломанный) метод:

    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));
    }

Я был бы очень рад использовать другую реализацию QueryBase в сервисе RetrieveMultiple.

Ответы [ 2 ]

0 голосов
/ 24 января 2019

Первичный ключ устанавливается CRM при создании объекта и соответствует формату «имя объекта» + «идентификатор», следующий формат не является хаком .

Если вас это не устраивает, я бы воспользовался сервисом метаданных, чтобы получить подробную информацию один раз.

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

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

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

Я не совсем уверен, с чем это связано, вероятно, вы делаете несколько вызовов службы для каждой сущности, один дополнительный вызов метаданных не повредит. Что касается ожидания, что сервер «просто знает» эту информацию; в любом случае, вероятно, придется запросить таблицы метаданных.

Наконец, если кто-то должен предоставить вам имена сущностей, вы также можете запросить поле первичного ключа.

0 голосов
/ 24 января 2019

Поскольку «взломанный» метод должен работать подавляющее большинство времени, возможно, сначала попробуйте «взломанный» метод, добавив id к имени сущности. Если это не удается, извлеките метаданные объекта, чтобы получить primaryId.

...