Compartilhar via


Trabalhando com dados (versão prévia)

[Este artigo faz parte da documentação de pré-lançamento e está sujeito a alterações.]

Neste artigo, demonstramos um código de exemplo que usa o SDK para trabalhar com metadados e dados do Dataverse. Certifique-se de ler Introdução (versão prévia) primeiro antes de continuar com este artigo.

Operações básicas

Aqui está um código de exemplo que opera na tabela da conta.

from azure.identity import InteractiveBrowserCredential
from PowerPlatform.Dataverse.client import DataverseClient

base_url = "https://<myorg>.crm.dynamics.com"
client = DataverseClient(base_url=base_url, credential=InteractiveBrowserCredential())

# Create an account and set some properties (returns list[str] of new GUIDs)
account_id = client.create("account", {"name": "Acme, Inc.", "telephone1": "555-0100"})[0]

# Read an account 
account = client.get("account", account_id)

# Update an account (returns None)
client.update("account", account_id, {"telephone1": "555-0199"})

# Delete an account
client.delete("account", account_id)

Operações em massa

Aqui, mostramos alguns exemplos que fazem atualizações em massa.

# Bulk update (broadcast) – apply same patch to several IDs
ids = client.create("account", [
    {"name": "Contoso"},
    {"name": "Fabrikam"},
])
client.update("account", ids, {"telephone1": "555-0200"})  # broadcast patch

# Bulk update (1:1) – list of patches matches list of IDs
client.update("account", ids, [
    {"telephone1": "555-1200"},
    {"telephone1": "555-1300"},
])
print({"multi_update": "ok"})

Aqui, mostramos um exemplo que cria várias contas. Passe uma lista de cargas úteis para create(logical_name, payloads) a fim de invocar a ação associada à coleção Microsoft.Dynamics.CRM.CreateMultiple. O método retorna list[str] dos IDs de registros criados.

# Bulk create accounts (returns list of GUIDs)
payloads = [
    {"name": "Contoso"},
    {"name": "Fabrikam"},
    {"name": "Northwind"},
]
ids = client.create("account", payloads)
assert isinstance(ids, list) and all(isinstance(x, str) for x in ids)
print({"created_ids": ids})

Informações adicionais sobre operações em massa:

  • Retorna None (o mesmo que uma única atualização) para manter a semântica consistente.
  • Transmissão X por registro é determinado pela possibilidade do parâmetro changes ser um dicionário ou uma lista.
  • Ao se construir alvos da ação UpdateMultiple, o atributo de chave primária é injetado automaticamente.
  • Se algum conteúdo omitir @odata.type, ele será carimbado automaticamente (pesquisa de nome lógico em cache).
  • A resposta inclui apenas IDs – o SDK retorna essas cadeias de caracteres GUID.
  • A criação de registro único retorna uma lista de elemento único de GUIDs.
  • A pesquisa de metadados para @odata.type é realizada uma vez por conjunto de entidades (em cache na memória).

Carregamento de arquivo

Aqui estão alguns exemplos de como carregar um arquivo chamado 'test.pdf' na coluna Arquivo chamada "sample_filecolumn" de um registro de conta. O primeiro exemplo é para um tamanho de arquivo menor que 128 MB, enquanto o segundo exemplo é para um tamanho de arquivo com mais de 128 MB.

client.upload_file('account', record_id, 'sample_filecolumn', 'test.pdf')
client.upload_file('account', record_id, 'sample_filecolumn', 'test.pdf', mode='chunk', if_none_match=True)

Informações adicionais sobre uploads de arquivo:

  • upload_file escolhe um dos três métodos a serem usados com base no tamanho do arquivo. Se o tamanho do arquivo for menor que 128 MB, o SDK usará upload_file_small, caso contrário, o SDK usará upload_file_chunk
  • upload_file_small faz uma única chamada à API Web e dá suporte apenas ao tamanho < do arquivo de 128 MB.
  • upload_file_chunk usa PATCH com Content-Range para carregar o arquivo (mais alinhado com o padrão HTTP em comparação com as mensagens do Dataverse). Ele consiste em dois estágios – 1. Solicitação PATCH para obter os cabeçalhos usados para upload real e 2. Upload atual em segmentos. A função usa o OData x-ms-chunk-size retornado no primeiro estágio para determinar o tamanho da parte (normalmente 4 MB) e, em seguida, usa Content-Range e Content-Length como metadados para o upload. O número total de chamadas à API Web é o número de blocos + 1.

Recuperar vários itens com paginação

Use a get função para transmitir resultados página a página. Você pode limitar o total de resultados com $top e sugerir o tamanho por página com o page_size parâmetro. O SDK define internamente o cabeçalho de preferência do OData odata.maxpagesize.

pages = client.get(
    "account",
    select=["accountid", "name", "createdon"],
    orderby=["name asc"],
    top=10,          # stop after 10 total rows (optional)
    page_size=3,     # ask for ~3 per page (optional)
)

total = 0
for page in pages: # each page is a list[dict]
    print({"page_size": len(page), "sample": page[:2]})
    total += len(page)
print({"total_rows": total})

Aqui está uma lista de parâmetros com suporte em que todos são opcionais, exceto logical_name.

  • logical_name: str — Nome lógico (singular), por exemplo, "conta".
  • select: list[str] | None — Columns -> $select (união por vírgula).
  • filter: str | None — OData $filter expression (por exemplo, contains(name,'Acme') e statecode eq 0).
  • orderby: list[str] | None – Classificar expressões –> $orderby (vírgula unida).
  • top: int | None — Global cap via $top (aplicado na primeira solicitação; o serviço é aplicado em várias páginas).
  • expand: list[str] | None — Expansões de navegação -> $expand; pass raw clauses (e.g., primarycontactid($select=fullname,emailaddress1)).
  • page_size: int | Nenhum — dica por página usando Prefer: odata.maxpagesize=<N> (não garantido; a última página pode ser menor).

Aqui está uma lista de valores retornados e semântica.

  • $select, $filter, $orderby, $expand, $top mapeie diretamente para opções de consulta OData correspondentes na primeira solicitação.
  • $top limite total de linhas; o serviço pode particionar essas linhas em várias páginas.
  • page_size (Prefer: odata.maxpagesize) é uma dica; o servidor decide os limites reais da página.
  • Retorna um gerador que gera páginas não vazias (list[dict]). Páginas vazias são ignoradas.
  • Cada lista gerada corresponde a uma página de valor da API Web.
  • A iteração é interrompida quando não resta nenhum @odata.nextLink (ou quando $top é satisfeito no lado do servidor).
  • O gerador não materializa todos os resultados; as páginas são buscadas de maneira lenta.

Vamos ver um exemplo com todos os parâmetros compatíveis mais a resposta esperada.

pages = client.get(
  "account",
  select=["accountid", "name", "createdon", "primarycontactid"],
  filter="contains(name,'Acme') and statecode eq 0",
  orderby=["name asc", "createdon desc"],
  top=5,
  expand=["primarycontactid($select=fullname,emailaddress1)"],
  page_size=2,
)

for page in pages:  # page is list[dict]
# Expected page shape (illustrative)
# [
# {
# "accountid": "00000000-0000-0000-0000-000000000001"
# "name": "Acme West"
# "createdon": "2025-08-01T12:34:56Z"
# "primarycontactid": {
# "contactid": "00000000-0000-0000-0000-0000000000aa"
# "fullname": "Jane Doe"
# "emailaddress1": "<jane@acme.com>"
# }
# "@odata.etag": "W/\"123456\""
# }
#
# ]
  print({"page_size": len(page)})

Metadados da tabela

Vamos dar uma olhada no código de exemplo para trabalhar com uma tabela personalizada.

# Support enumerations with labels in different languages
class Status(IntEnum):
    Active = 1
    Inactive = 2
    Archived = 5
    __labels__ = {
        1033: {
            "Active": "Active",
            "Inactive": "Inactive",
            "Archived": "Archived",
        },
        1036: {
            "Active": "Actif",
            "Inactive": "Inactif",
            "Archived": "Archivé",
        }
    }

# Create a simple custom table and a few columns
info = client.create_table(
    "SampleItem",  # friendly name; defaults to SchemaName new_SampleItem
    {
        "code": "string",
        "count": "int",
        "amount": "decimal",
        "when": "datetime",
        "active": "bool",
        "status": Status,
    },
)

logical = info["entity_logical_name"]  # for example, "new_sampleitem"

# Create a record in the new table
# Set your publisher prefix (used when creating the table). If you used the default, it's "new".
prefix = "new"
name_attr = f"{prefix}_name"
id_attr = f"{logical}id"

rec_id = client.create(logical, {name_attr: "Sample A"})[0]

# Clean up
client.delete(logical, rec_id)          # delete record
client.delete_table("SampleItem")       # delete table (friendly name or explicit schema new_SampleItem)

Informações adicionais sobre como trabalhar com metadados de tabela personalizados:

  • create sempre retorna uma lista de GUIDs (length=1 para entrada única).
  • update e delete retorne None para interfaces simples e múltiplas.
  • A passagem de uma lista das cargas úteis para create dispara uma criação em massa e retorna list[str] de IDs.
  • get dá suporte à recuperação de um único registro com ID de registro ou paginação por meio de conjuntos de resultados (é preferível selecionar para limitar as colunas).
  • Para métodos CRUD que levam um ID de registro, passe a cadeia de caracteres GUID de 36 caracteres (hifenizada). Parênteses ao redor do GUID são aceitos, mas não são necessários.
  • Consultas SQL são executadas diretamente nos pontos de extremidade de conjuntos de entidades usando o parâmetro ?sql=. Somente subconjunto compatível (SELECT único, WHERE/TOP/ORDER BY opcional, alias). Construções sem suporte são rejeitadas pelo serviço.

Usando pandas com o SDK

PandasODataClient é um wrapper fino que envolve o cliente de baixo nível. Todos os métodos aceitam nomes lógicos (singulares) (por exemplo, conta, new_sampleitem), e não nomes de conjunto de entidades (plural), sendo isso suportado. Consulte o exemplo de repositório de origem do SDK chamado 'quickstart_pandas.py' para um DataFrame fluxo de trabalho.

Consulte também