{"componentChunkName":"component---src-templates-blog-post-js","path":"/blog/dataverse-alternate-keys-upsert-integracao/","result":{"data":{"markdownRemark":{"frontmatter":{"title":"Dataverse: alternate keys e upsert para integracoes idempotentes","description":"Como usar alternate keys e a operacao Upsert no Dataverse para integracoes que nao duplicam registros nem quebram em reprocessamento, com foco em performance e concorrencia.","date":"17 de setembro de 2026","thumbnail":null},"html":"<p>Toda integracao que grava no Dataverse a partir de um sistema externo mais cedo ou mais tarde esbarra na mesma pergunta: este registro ja existe? Sem uma resposta confiavel, o fluxo cai em um dos dois extremos — duplica dados a cada reprocessamento ou vive fazendo um Get antes de cada Create para conferir. Alternate keys e a operacao Upsert existem justamente para resolver isso de forma nativa, sem gambiarra de lookup manual.</p>\n<p><strong>O que e uma alternate key e por que ela muda o jogo</strong></p>\n<p>O GUID (identificador primario) de uma linha do Dataverse so faz sentido dentro do Dataverse. O sistema externo — ERP, e-commerce, legado SQL — nao conhece esse GUID; ele conhece o proprio codigo de negocio: numero de pedido, CPF/CNPJ, SKU, matricula. A alternate key permite declarar que uma ou mais colunas formam uma chave unica alternativa para aquela tabela. A partir dai, voce consegue referenciar uma linha pela chave de negocio (<code>accounts(cnpj='12345678000190')</code>) em vez de precisar do GUID.</p>\n<p>Por tras, o Dataverse cria um indice unico no SQL Server que sustenta a chave. Duas consequencias praticas:</p>\n<ul>\n<li>A unicidade passa a ser garantida pelo banco, nao pela sua logica de fluxo. Duas tentativas simultaneas de criar o mesmo CNPJ nao geram dois registros — a segunda falha com violacao de chave.</li>\n<li>Buscas por essa chave ficam rapidas, porque batem no indice em vez de fazer scan.</li>\n</ul>\n<p>Uma alternate key pode ser composta (ate cinco colunas) e aceita lookup, texto, numero, decimal, data e option set como componentes. O que ela <strong>nao</strong> aceita bem sao colunas com valores nulos frequentes — a chave depende de todos os componentes estarem preenchidos.</p>\n<p><strong>Upsert: create ou update em uma unica operacao</strong></p>\n<p>Com a chave declarada, a operacao Upsert faz o roteamento automatico: se existe uma linha com aquela chave, ela e atualizada; se nao existe, e criada. Isso e o que torna a integracao idempotente — reprocessar a mesma mensagem duas vezes leva ao mesmo estado final, sem duplicar e sem estourar erro de \"ja existe\".</p>\n<p>No SDK, o <code>UpsertRequest</code> recebe a entidade com a chave preenchida (<code>new Entity(\"account\", keyAttributeCollection)</code>) e resolve tudo em um round-trip. Na Web API, um <code>PATCH</code> para <code>/accounts(cnpj='...')</code> faz o mesmo: cria se nao existe, atualiza se existe. No Power Automate, a acao <strong>Upsert a row</strong> do connector do Dataverse expoe esse comportamento usando a alternate key como identificador da linha.</p>\n<p>Comparado ao padrao ingenuo de \"Get, testar se veio vazio, senao Create\", o Upsert elimina:</p>\n<ol>\n<li>Uma chamada de rede (o Get separado).</li>\n<li>A janela de corrida entre o Get e o Create, onde dois processos podem ambos concluir que a linha nao existe.</li>\n</ol>\n<p><strong>Referenciar relacionamentos sem carregar o GUID</strong></p>\n<p>Um ganho que passa despercebido: alternate keys tambem servem para preencher lookups na hora de gravar. Se voce esta importando pedidos e cada pedido aponta para uma conta pelo CNPJ, nao precisa primeiro buscar o GUID da conta para depois setar o lookup. Voce seta a referencia pela chave alternativa da conta diretamente (<code>\"account@odata.bind\": \"/accounts(cnpj='...')\"</code> na Web API, ou <code>EntityReference</code> com <code>KeyAttributes</code> no SDK). Isso reduz drasticamente o numero de chamadas em cargas com muitos relacionamentos.</p>\n<p><strong>Cuidados de producao que costumam morder</strong></p>\n<p>Alternate key nao e de graca em escala. Alguns pontos que aparecem quando o volume cresce:</p>\n<ul>\n<li><strong>Custo de escrita.</strong> Cada indice unico adicional deixa os inserts e updates um pouco mais caros, porque o indice precisa ser mantido. Nao saia criando alternate key em toda tabela; use onde a integracao realmente precisa referenciar por chave de negocio.</li>\n<li><strong>Criacao assincrona do indice.</strong> Ao adicionar uma alternate key numa tabela ja populada, o Dataverse cria o indice em background. Ate o status virar Active, a chave nao esta disponivel para uso — verifique o estado antes de disparar a carga.</li>\n<li><strong>Chave sobre lookup e concorrencia.</strong> Alternate keys que incluem colunas lookup sao poderosas para modelar unicidade contextual (ex.: um item por pedido), mas herdam a fragilidade de nulos e exigem que o lookup ja esteja resolvido no momento da gravacao.</li>\n<li><strong>Normalizacao de dados.</strong> Se o CNPJ chega ora com pontuacao, ora sem, a chave nao vai reconciliar os dois formatos — para ela sao valores diferentes. Padronize o valor antes de gravar; a chave nao normaliza por voce.</li>\n<li><strong>Colisao legitima.</strong> Upsert atualiza a linha existente. Se a chave estiver mal escolhida (larga demais ou solta demais), voce pode sobrescrever silenciosamente dados de outro registro. Escolha a chave que realmente identifica a entidade de negocio, nao algo conveniente.</li>\n</ul>\n<p><strong>Um roteiro pratico de decisao</strong></p>\n<ol>\n<li>A tabela recebe dados de um sistema externo que tem seu proprio identificador estavel? Se sim, crie uma alternate key sobre esse identificador.</li>\n<li>O identificador externo e imutavel? Alternate key sobre um campo que muda quebra a reconciliacao — prefira algo que nunca muda no sistema de origem.</li>\n<li>Vai referenciar relacionamentos na carga? Aproveite as alternate keys das tabelas relacionadas para bindar lookups sem GUID.</li>\n<li>Substitua os padroes de Get+Create por Upsert e ganhe idempotencia de graca.</li>\n<li>Meça o impacto de escrita se a tabela for de alto volume; remova alternate keys que nao servem a nenhuma integracao.</li>\n</ol>\n<p>Integracoes idempotentes sao a diferenca entre um pipeline que voce pode reexecutar com tranquilidade e um que exige um mutirao de limpeza de duplicatas toda vez que algo falha no meio. Na Dynamic Soluções, tratamos alternate keys e Upsert como parte do desenho de qualquer integracao critica com o Dataverse — junto com tratamento de erros, ALM em solucao gerenciada e governanca. Se sua empresa esta integrando o Dataverse com sistemas externos e sofrendo com duplicidade ou reprocessamento fragil, vale estruturar isso desde o design.</p>\n<p>Every integration that writes to Dataverse from an external system sooner or later hits the same question: does this record already exist? Without a reliable answer, the flow falls into one of two extremes — it duplicates data on every reprocess, or it keeps doing a Get before each Create just to check. Alternate keys and the Upsert operation exist precisely to solve this natively, without a manual lookup workaround.</p>\n<p><strong>What an alternate key is and why it changes the game</strong></p>\n<p>The GUID (primary identifier) of a Dataverse row only makes sense inside Dataverse. The external system — ERP, e-commerce, legacy SQL — doesn't know that GUID; it knows its own business code: order number, tax ID, SKU, employee number. An alternate key lets you declare that one or more columns form an alternate unique key for that table. From then on, you can reference a row by its business key (<code>accounts(cnpj='12345678000190')</code>) instead of needing the GUID.</p>\n<p>Under the hood, Dataverse creates a unique index in SQL Server backing the key. Two practical consequences:</p>\n<ul>\n<li>Uniqueness is now guaranteed by the database, not by your flow logic. Two simultaneous attempts to create the same tax ID won't produce two records — the second fails with a key violation.</li>\n<li>Lookups by that key are fast, because they hit the index instead of scanning.</li>\n</ul>\n<p>An alternate key can be composite (up to five columns) and accepts lookup, text, number, decimal, date, and option set as components. What it does <strong>not</strong> handle well are columns with frequent null values — the key depends on all components being filled.</p>\n<p><strong>Upsert: create or update in a single operation</strong></p>\n<p>With the key declared, the Upsert operation routes automatically: if a row with that key exists, it's updated; if not, it's created. This is what makes the integration idempotent — reprocessing the same message twice leads to the same final state, without duplicating and without throwing an \"already exists\" error.</p>\n<p>In the SDK, <code>UpsertRequest</code> takes the entity with the key filled in (<code>new Entity(\"account\", keyAttributeCollection)</code>) and resolves everything in one round-trip. In the Web API, a <code>PATCH</code> to <code>/accounts(cnpj='...')</code> does the same: creates if missing, updates if present. In Power Automate, the Dataverse connector's <strong>Upsert a row</strong> action exposes this behavior using the alternate key as the row identifier.</p>\n<p>Compared with the naive \"Get, test if empty, otherwise Create\" pattern, Upsert eliminates:</p>\n<ol>\n<li>A network call (the separate Get).</li>\n<li>The race window between the Get and the Create, where two processes might both conclude the row doesn't exist.</li>\n</ol>\n<p><strong>Referencing relationships without loading the GUID</strong></p>\n<p>An often-overlooked win: alternate keys also help set lookups when writing. If you're importing orders and each one points to an account by tax ID, you don't need to first fetch the account's GUID to then set the lookup. You set the reference by the account's alternate key directly (<code>\"account@odata.bind\": \"/accounts(cnpj='...')\"</code> in the Web API, or <code>EntityReference</code> with <code>KeyAttributes</code> in the SDK). This drastically reduces the number of calls in loads with many relationships.</p>\n<p><strong>Production caveats that tend to bite</strong></p>\n<p>Alternate keys aren't free at scale. Some points that show up as volume grows:</p>\n<ul>\n<li><strong>Write cost.</strong> Each additional unique index makes inserts and updates slightly more expensive, because the index has to be maintained. Don't create alternate keys on every table; use them where the integration genuinely needs to reference by business key.</li>\n<li><strong>Asynchronous index creation.</strong> When you add an alternate key to an already-populated table, Dataverse builds the index in the background. Until the status turns Active, the key isn't available — check the state before firing the load.</li>\n<li><strong>Keys over lookups and concurrency.</strong> Alternate keys that include lookup columns are powerful for modeling contextual uniqueness (e.g., one line item per order), but they inherit the null fragility and require the lookup to already be resolved at write time.</li>\n<li><strong>Data normalization.</strong> If the tax ID sometimes arrives with punctuation and sometimes without, the key won't reconcile the two formats — to it they're different values. Standardize the value before writing; the key won't normalize for you.</li>\n<li><strong>Legitimate collision.</strong> Upsert updates the existing row. If the key is poorly chosen (too broad or too loose), you may silently overwrite another record's data. Choose the key that truly identifies the business entity, not something convenient.</li>\n</ul>\n<p><strong>A practical decision path</strong></p>\n<ol>\n<li>Does the table receive data from an external system that has its own stable identifier? If so, create an alternate key on that identifier.</li>\n<li>Is the external identifier immutable? An alternate key over a changing field breaks reconciliation — prefer something that never changes in the source system.</li>\n<li>Will you reference relationships in the load? Leverage the related tables' alternate keys to bind lookups without a GUID.</li>\n<li>Replace the Get+Create patterns with Upsert and get idempotency for free.</li>\n<li>Measure the write impact if the table is high-volume; remove alternate keys that serve no integration.</li>\n</ol>\n<p>Idempotent integrations are the difference between a pipeline you can rerun with confidence and one that requires a duplicate-cleanup effort every time something fails mid-way. At Dynamic Soluções, we treat alternate keys and Upsert as part of the design of any critical Dataverse integration — alongside error handling, ALM in a managed solution, and governance. If your company is integrating Dataverse with external systems and suffering from duplication or fragile reprocessing, it's worth structuring this from the design stage.</p>"}},"pageContext":{"slug":"/blog/dataverse-alternate-keys-upsert-integracao/","previousPost":null,"nextPost":{"frontmatter":{"title":"Power Apps Component Framework: reuso de UI corporativa com PCF"},"fields":{"slug":"/blog/power-apps-component-framework-pcf-reuso-controles/"}}}},"staticQueryHashes":["2269431855"]}