Pessoal,
Uma nova feacture disponibilizada no Update 1 do CRM 2015 é a possibilidade do controle de transações para processos em backgroup (batching), que é concebida pela classe “ExecuteTransactionRequest“.
A classe “ExecuteTransactionRequest” é muito semelhante a “ExecuteMultipleRequest“, porém temos como garantia o conceito de transação, deste modo, qualquer erro retornado durante o acesso via SDK fará com que todos os demais registros que já foram inseridos no banco de dados sejam retrocedidos (rollback), aliás, na prática os registros anteriores foram adicionados, mas não foram “commitados”, só serão quando a totalidade de registros for inserida com sucesso.
Bom, mas para qual propósito devemos utilizar o “ExecuteTransaction”?
O conceito transação também traz consigo a ideia de Atomicidade, ou seja, existem cenários que desejamos que todos registros sejam carregados ou nenhum caso exista ao menos um problema. Um bom exemplo pode ser dado no caso de uma integração de dados diária, cujo dados são informados por outro sistema, que realiza uma carga de Clientes (accounts), onde desejamos que sejam importados todos os novos clientes, a única validação feita é a existência de um valor no atributo “CNPJ” (A regra de validação foi criada em um plugin da entidade Account). Caso algum cliente não possua seu CNPJ informado, precisamos que todos os demais desta mesma integração, que já foram inseridos sejam removidos do CRM
A diferença básica quando comparamos com o ExecuteMultiple, é que o ExecuteMultiple não controla transação, temos a propriedade “ContinueOnError” que pode ou não continuar as execuções mesmo após um erro, porém, os registros anteriormente inseridos não serão removidos, pois já foram “commitados” no banco de dados do CRM.
Em relação a performance fiz alguns testes com 100, 500 e 1000 registros em comparação com o ExecuteMultiple e os tempos são muito similares, não existe ganho ou perda de desempenho.
Abaixo criei um exemplo prático
public void ExecuteTransaction() { int cont = 100; DateTime inicio = DateTime.Now; Console.WriteLine(); Console.WriteLine("EXECUTETRANSACTION " + cont + " Data Início: " + inicio); try { CreateRequest createRequest; // Create an ExecuteTransactionRequest object. ExecuteTransactionRequest transactions = new ExecuteTransactionRequest() { ReturnResponses = true, // Para retornar os objetos Response // Create an empty organization request collection. Requests = new OrganizationRequestCollection() }; // Percorre o contador adicionando CreateRequests da entidade Account for (int i = 0; i < cont; i++) { // Cria o objeto Entity com uma nova Account Entity account = new Entity("account"); account.Attributes.Add("name", "EXECUTETRANSACTION_" + i + " " + DateTime.Now); createRequest = new CreateRequest { Target = account }; transactions.Requests.Add(createRequest); // Desabilitar para simular um erro no CRM //if (i == 4) //{ // // Cria o objeto Entity com uma nova Account // Entity account1 = new Entity("account"); // account1.Attributes.Add("fax", "123456789012345678901234567890123456789012345678901234567890"); // Atributo fax com mais de 50 caracteres, irá provovar um erro // createRequest = new CreateRequest { Target = account1 }; // transactions.Requests.Add(createRequest); //} } // Executa as Transações ExecuteTransactionResponse responseWithResults = (ExecuteTransactionResponse)service.Execute(transactions); } catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> ex) { ExecuteTransactionFault fault = (ExecuteTransactionFault)ex.Detail; int faultedIndex = fault.FaultedRequestIndex; // Caso ocorra algum erro podemos verificar qual registro teve o problema través do "FaultedRequestIndex" } DateTime fim = DateTime.Now; Console.WriteLine(); Console.WriteLine("EXECUTETRANSACTION " + cont + " Data Início: " + inicio + " Data Fim: " + fim); }
Alguns pontos a considerar:
- Temos as mesmas restrições da classe ExecuteMultipleRequest em relação a quantidade de objetos (requests) e limites de execuções simultâneas
- Não existem restrições para tipos diferentes de objetos de request (Create, Update, Delete e etc), porém não podemos ter outros ExecuteTransaction ou ExecuteMultiple
- Devido ao uso de um único bloco transacional os registros que ainda não foram “commitados” ficam bloqueados, por tanto não generalize e pense bem antes de implementar
[]’s,
Tiago Cardoso