Umas das novidades mais legais do Microsoft Dynamics CRM 4.0 é a possibilidade de criar relacionamento N:N (Many to Many) entre as entidades, este tipo de relacionamento me possibilita por exemplo dizer que um contato contém vários contatos e que vários contatos participam de vários contratos diferentes.

Claro que, para quem conhece, não existe relacionamento N:N dentro do banco de dados, ou é N:1 ou 1:N, então como isto é possível....a resposta é tão simples, ao solicitarmos a criação de um relacionamento do tipo Many to Many entre duas entidades, o CRM, de forma implícita, cria uma tabela intermediária no banco de dados que contém apenas quatro atributos, sendo dois deles as chaves primárias das entidades relacionadas:

tabela

Abstraindo todas as colunas das entidades laterais, a figura acima mostra a tabela de referencia para o relacionamento N:N.

Legal, vamos para o divertido, como trabalhar com está novidade via SDK...primeiro vem a noticia chata, as tabelas intermediarias não são visualizadas como entidades então não podemos trabalhar com o Retrieve nem com o RetrieveMultiple para poder Capturar os dados, o mesmo vale para a gravação de dados, não podemos usar os métodos comuns para este procedimento, porem não é difícil realizar tais operações.

Criando Dados em entidades N:N

O processo de gravação é bem simples, para isto contamos com a classe AssociateEntitiesRequest que junto com a classe Moniker serão os responsáveis por gravar os dados no nosso BD:

  1. Para iniciar, deve-se adicionar a Referencia ao endereço http://ENDEREÇO_crm/mscrmservices/2007/CrmService.asmx sob o nome de CrmSdk.
  2. No topo da classe, vamos instanciar as bibliotecas do CRM através do comando using CrmSdk;

Vamos criar uma classe void responsável apenas por salvar os Contatos que fazem relacionamento com os contratos:

public void SalvaContato_Contrato()

{

  //Instância uma nova conexão ao CRM
  CrmService service = new CrmService();
  service.PreAuthenticate = true;
  //Instância o Token de autenticação
  CrmAuthenticationToken Token = new CrmAuthenticationToken();
  Token.AuthenticationType = 0;//0 = Autenticação por AD
  Token.OrganizationName = "Olavo";
  //Nome da Organização ao qual vamos nos conectar
  service.CrmAuthenticationTokenValue = Token;
  //Informa usuário que está conectando
  service.Credentials = new System.Net.NetworkCredential
  ("Olavo", "----------------", "CRM4");
  //Inicia o Request
  AssociateEntitiesRequest associateRequest = new AssociateEntitiesRequest();
  //Moniker 1 será responsável pelos dados da entidade Contact
  associateRequest.Moniker1 = new Moniker();
  associateRequest.Moniker1.Id = new Guid
    ("cd06d480-40b9-de11-a3af-00155d013108");
  associateRequest.Moniker1.Name = EntityName.contact.ToString();
  //Moniker 2 será responsavel pelos dados da entidade Contract
  associateRequest.Moniker2 = new Moniker();
  associateRequest.Moniker2.Id = new Guid
   ("EC1864D0-40B9-DE11-A3AF-00155D013108");
  associateRequest.Moniker2.Name = EntityName.contract.ToString();
  //Informa o nome do relacionamento
  associateRequest.RelationshipName = "servicecontractcontacts_association";
  AssociateEntitiesResponse response = 
   (AssociateEntitiesResponse)service.Execute(associateRequest);

Capturando Dados da tabela de interseção

Capturar os dados contidos nas tabelas de interseção (intermediarias) é um processo simples, porém bem diferente do usual Retrieve e do RetrieveMultiple. Por se tratar de tabelas de interseção e não de entidades propriamente ditas, o CRM não consegue realizar consultas diretas dentro dela, tanto que se você tentar pesquisar o nome da tabela através do Enum EntityName, verá que não consta o nome da tabela de interseção.

A partir de agora, para realizarmos este tipo de consulta, teremos de usar o método Fetch da classe CrmService trabalha com consulta em XML e que retorna o resultado também em XML.

O código para realizar a consulta fica mais ou menos assim:

   public Guid RetornaUsuario_Contrato()
   {
    //Instância uma nova conexão ao CRM
    CrmService service = new CrmService();
             service.PreAuthenticate = true;
             //Instância o Token de autenticação
             CrmAuthenticationToken Token = new CrmAuthenticationToken();
             Token.AuthenticationType = 0;//0 = Autenticação por AD
             Token.OrganizationName = "Olavo";
               //Nome da Organização ao qual vamos nos conectar
              service.CrmAuthenticationTokenValue = Token;
              //Informa usuário que está conectando
             service.Credentials = new System.Net.NetworkCredential
               ("Olavo", "----------------", "CRM4");
               //Monta o XML de consulta
              //Entity name = <INFORMA Nome interseção de tabela da o>
              //Caso se queria utilizar mais de um Condition, 
              //deve-se acrescentar no filter type = 'and'>
              string Consulta =
             @"<FETCH mapping="logical">
                  <ENTITY name="servicecontractcontacts">
                      <ALL-ATTRIBUTES />
                          <FILTER>
                              <CONDITION operator="eq" attribute="contractid" 
                               value='EC1864D0-40B9-DE11-A3AF-00155D013108' />
                           </FILTER>
                   </ENTITY>
                </FETCH>";
              //Captura resultado
              string Resultado = service.Fetch(Consulta);
              //Trabalhando com o XML retornado
              System.Xml.XmlDocument Document = new System.Xml.XmlDocument();
             Document.LoadXml(Resultado);
             System.Xml.XmlNodeList XmlNodes =
                 Document.SelectNodes("resultset/result/contactid");
             if (XmlNodes.Count > 0)
                 return new Guid(XmlNodes[0].InnerText);
              return Guid.Empty; }

É isto pessoal. Nada de muito complicado, porem extremamente útil quando se tem entidades se relacionamento de N:N no Microsoft Dynamics CRM 4.0