Dynamics 365 – Entidade Virtual SEM Chave Primária do tipo GUID (Parte 1/2)


Olá pessoal,

Continuo pesquisando, testando e escrevendo sobre Entidades Virtuais (Virtual Entities), neste post, irei demonstrar como criar uma entidade virtual que não possui como chave primária um atributo do tipo GUID!

Isso mesmo, vou explicar como “driblar” o Dynamics 365, pois atualmente uma chave primária do tipo GUID é uma das exigências para utilizarmos entidades virtuais.

Para aquelas que ainda não leram meus posts anteriores, recomendo a leitura para auxiliar o entendimento deste post, vale a pena dar uma conferida! Seguem alguns links:

Dynamics 365 – Relacionar Entidade Virtual (Virtual Entity) com Entidade Nativa/Cutomizada
Dynamics 365 – Provedor de Dados Customizado/Custom Data Provider (Parte 1/3)
Dynamics 365 – Provedor de Dados Customizado/Custom Data Provider (Parte 2/3)
Dynamics 365 – Provedor de Dados Customizado/Custom Data Provider (Parte 3/3)

Bom, voltando ao tema do post, como já sabemos entidades virtuais possuem algumas limitações, uma delas é que a chave primária do serviço externo deve ser um GUID, porém o serviço externo dificilmente terá o GUID do Dynamics persistido em seu retorno. O mais natural é que Dynamics 365 e serviço externo utilizem como chave primária uma chave de negócios.

Deste modo, como seria possível recuperar registros de um entidade virtual sem chave primária do tipo GUID ou recuperar registros relacionados a um contato, sendo que não temos o atributo “contactid” no serviço externo?

Esta série de dois posts irá explicar como! Irei mostrar como criar um provedor de dados customizado que elimina a necessidade de termos atributos do tipo GUID, tanto para chave primária quanto para permitir o relacionamento entre duas entidades (virtual e nativa/customizada).

Contexto

Antes de iniciar a falar do código, preciso dar um pouco de contexto. Assim como nos posts anteriores, continue utilizando um relacionamento entre Contato (contact) e uma entidade virtual chamada External Activity (new_externalentity). Deste modo, embora eu tenha sido obrigado a fazer um relacionamento de 1:N (1 contato > N external activities), o serviço externo não respeita/entende o que é um contactid, mas sim um atributo que criei chamado “External Activity Key” (new_externalactivitykey), este atributo é a chave de negócios única que relaciona as duas entidades.

Resumindo, o cenário deste post é quando a API do Serviço externo não possui a chave primária do tipo Guid, bem como um atributo do tipo Guid para determinar o relacionamento entre contatos e external activities.

API

Irei utilizar como API, algo muito parecido do que já fiz anteriormente neste post.

Aqui vai um printscreen to projeto no Visual Studio para ajudar a se localizar:

Abaixo minha Model (ExternalActivity.cs), veja que estou usando a mesma do post anterior, com isso não precisarei criar uma nova entidade virtual:

using System;

namespace DemoJSON
{
    public class ExternalActivity
    {
        public int ExternalActivityKey { get; set; }

        public int ExternalContactKey { get; set; }

        public string Subject { get; set; }

        public string Details { get; set; }

        public string From { get; set; }

        public string To { get; set; }
    }
}

Sim! No Guids!

Agora a Interface de Serviço (IJSONService.cs):

using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Web;

namespace DemoJSON
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
    [ServiceContract]
    public interface IJSONService
    {
        [OperationContract]
        [WebInvoke(UriTemplate = "ExternalActivityByExternalActivityKey/{externalActivityKey}", Method = "GET", BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        List<ExternalActivity> ExternalActivityByExternalActivityKey(string externalActivityKey);

        [OperationContract]
        [WebInvoke(UriTemplate = "ExternalActivitiesByExternalContactKey/{externalContactKey}", Method = "GET", BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        List<ExternalActivity> ExternalActivitiesByExternalContactKey(string externalContactKey);
    }
}

Acima, existem dois métodos, um para ser utilizado no Retrieve (ExternalActivityByExternalActivityKey), que recebe como parâmetro externalActivityKey) e outro para o RetrieveMultiple (ExternalActivitiesByExternalContactKey, que recebe como parâmetro externalContactKey).

Vejam que estou utilizando as chaves de negócio ao invés de qualquer atributo do tipo Guid…

Vamos a implementação da interface com sua lógica (JSONService.cs):


using System;
using System.Collections.Generic;
using System.Linq;

namespace DemoJSON
{
    public class JSONService : IJSONService
    {
        public List<int> listExternalActivitiesKeys = new List<int>();

        public JSONService()
        {
            listExternalActivitiesKeys.Add(1);
            listExternalActivitiesKeys.Add(2);
            listExternalActivitiesKeys.Add(3);
            listExternalActivitiesKeys.Add(4);
            listExternalActivitiesKeys.Add(5);
            listExternalActivitiesKeys.Add(6);
            listExternalActivitiesKeys.Add(7);
            listExternalActivitiesKeys.Add(8);
            listExternalActivitiesKeys.Add(9);
            listExternalActivitiesKeys.Add(10);
            listExternalActivitiesKeys.Add(11);
            listExternalActivitiesKeys.Add(12);
            listExternalActivitiesKeys.Add(13);
            listExternalActivitiesKeys.Add(14);
            listExternalActivitiesKeys.Add(15);
            listExternalActivitiesKeys.Add(16);
            listExternalActivitiesKeys.Add(17);
            listExternalActivitiesKeys.Add(18);
            listExternalActivitiesKeys.Add(19);
            listExternalActivitiesKeys.Add(20);
            listExternalActivitiesKeys.Add(21);
            listExternalActivitiesKeys.Add(22);
            listExternalActivitiesKeys.Add(23);
            listExternalActivitiesKeys.Add(24);
            listExternalActivitiesKeys.Add(25);
            listExternalActivitiesKeys.Add(26);
            listExternalActivitiesKeys.Add(27);
            listExternalActivitiesKeys.Add(28);
            listExternalActivitiesKeys.Add(29);
            listExternalActivitiesKeys.Add(30);
            listExternalActivitiesKeys.Add(31);
            listExternalActivitiesKeys.Add(32);
            listExternalActivitiesKeys.Add(33);
            listExternalActivitiesKeys.Add(34);
            listExternalActivitiesKeys.Add(35);
            listExternalActivitiesKeys.Add(36);
            listExternalActivitiesKeys.Add(37);
            listExternalActivitiesKeys.Add(38);
            listExternalActivitiesKeys.Add(39);
            listExternalActivitiesKeys.Add(40);
            listExternalActivitiesKeys.Add(41);
            listExternalActivitiesKeys.Add(42);
            listExternalActivitiesKeys.Add(43);
            listExternalActivitiesKeys.Add(44);
            listExternalActivitiesKeys.Add(45);
            listExternalActivitiesKeys.Add(46);
            listExternalActivitiesKeys.Add(47);
            listExternalActivitiesKeys.Add(48);
            listExternalActivitiesKeys.Add(49);
            listExternalActivitiesKeys.Add(50);
        }

        public List<ExternalActivity> ExternalActivitiesByExternalContactKey(string paramExternalContactKey)
        {
            List<ExternalActivity> ExternalActivities = new List<ExternalActivity>();

            for (int i = 0; i < 1000; i++)
            {
                int externalContactKey = RandomInteger(5);
                int externalActivityKey = RandomInteger(5);

                if (i < 50)
                {
                    externalContactKey = 1;
                    externalActivityKey = listExternalActivitiesKeys[i];
                }

                ExternalActivities.AddRange(new List<ExternalActivity>
                {
                    new ExternalActivity()
                    {
                        ExternalActivityKey = externalActivityKey,
                        ExternalContactKey = externalContactKey,
                        From = RandomString(10),
                        To = RandomString(10),
                        Subject= RandomString(20),
                        Details = RandomString(100),
                    }
                });
            }

            if (!string.IsNullOrEmpty(paramExternalContactKey))
            {
                return ExternalActivities.Where(m => m.ExternalContactKey.Equals(Convert.ToInt32(paramExternalContactKey))).ToList();
            }
            else
            {
                return ExternalActivities;
            }
        }

        public List<ExternalActivity> ExternalActivityByExternalActivityKey(string paramExternalActivityKey)
        {
            List<ExternalActivity> ExternalActivities = new List<ExternalActivity>();

            for (int i = 0; i < 1000; i++)
            {
                int externalContactKey = RandomInteger(5);
                int externalActivityKey = RandomInteger(5);

                if (i < 50)
                {
                    externalContactKey = 1;
                    externalActivityKey = listExternalActivitiesKeys[i];
                }

                ExternalActivities.AddRange(new List<ExternalActivity>
                {
                    new ExternalActivity()
                    {
                        ExternalActivityKey = externalActivityKey,
                        ExternalContactKey = externalContactKey,
                        From = RandomString(10),
                        To = RandomString(10),
                        Subject= RandomString(20),
                        Details = RandomString(100),
                    }
                });
            }

            if (!string.IsNullOrEmpty(paramExternalActivityKey))
            {
                return ExternalActivities.Where(m => m.ExternalActivityKey.Equals(Convert.ToInt32(paramExternalActivityKey))).ToList();
            }
            else
            {
                return ExternalActivities;
            }
        }

        static Random random = new Random();

        public static string RandomString(int length)
        {
            const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            return new string(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());
        }

        public static int RandomInteger(int length)
        {
            const string chars = "0123456789";
            return Convert.ToInt32(new string(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray()));
        }
    }
}

Linhas destacadas:

9 à 63 – Criei uma lista fixa (hardcoded) contendo alguns External Activity Keys, para garantir que os dois métodos irão possuir os mesmos IDs, na “vida real”, você já tem isso!

74 à 78  e 113 à 117 – Novamente outra parte de código que “na vida real” não existe, mas nesta API de testes tive que garantir que os primeiros 50 registros de External Activity terão como Ids de 1 à 50 e todos pertencerão ao contato “1” (External Contact Key).

A configuração do Web.config também não mudou em comparação com o post anterior.

Bom, nossa API externa está pronta!

Vamos para o provedor de dados customizado! Este será meu próximo post, não percam!

[]’s,

Tiago

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.