Compartir por


Trabajar con datos (versión preliminar)

[Este artículo es documentación preliminar y está sujeto a modificaciones].

En este artículo, se muestra un código de ejemplo que usa el SDK para trabajar con datos y metadatos de Dataverse. Asegúrese de leer Introducción (versión preliminar) antes de continuar con este artículo.

Operaciones Básico

Este es un ejemplo de código que funciona en la tabla de cuentas.

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)

Operaciones masivas

Aquí se muestran un par de ejemplos que realizan actualizaciones masivas.

# 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"})

Aquí se muestra un ejemplo que crea varias cuentas. Pase una lista de cargas a create(logical_name, payloads) para invocar la acción enlazada a la colección de Microsoft.Dynamics.CRM.CreateMultiple. El método devuelve list[str] los identificadores de registro creados.

# 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})

Información adicional sobre las operaciones masivas:

  • Devuelve None (igual que una actualización única) para mantener la semántica coherente.
  • La elección entre transmisión y procesamiento por registro se determina según si el parámetro changes es un diccionario o una lista.
  • El atributo de clave principal se inserta automáticamente al construir destinos de acción UpdateMultiple .
  • Si alguna carga omite @odata.type, se marca automáticamente (búsqueda de nombres lógicos almacenados en caché).
  • La respuesta solo incluye identificadores: el SDK devuelve esas cadenas GUID.
  • La creación de un único registro devuelve una lista de un solo elemento de GUID.
  • La búsqueda @odata.type de metadatos se realiza una vez por conjunto de entidades (en memoria caché).

Carga de archivo

Estos son un par de ejemplos de carga de un archivo denominado "test.pdf" en la columna Archivo denominada "sample_filecolumn" de un registro de cuenta. El primer ejemplo es para un tamaño de archivo inferior a 128 MB, mientras que el segundo ejemplo es para un tamaño de archivo superior a 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)

Información adicional sobre las cargas de archivos:

  • upload_file elige uno de los tres métodos que se van a usar en función del tamaño del archivo. Si el tamaño del archivo es inferior a 128 MB, el SDK usa upload_file_small; de lo contrario, el SDK usa upload_file_chunk
  • upload_file_small realiza una sola llamada api web y solo admite el tamaño < de archivo 128 MB.
  • upload_file_chunk usa PATCH con content-Range para cargar el archivo (más alineado con el estándar HTTP en comparación con los mensajes de Dataverse). Consta de dos fases - 1. Solicitud PATCH para obtener los encabezados usados para la carga real y 2. Carga real en fragmentos. La función usa OData x-ms-chunk-size devuelto en la primera fase para determinar el tamaño del fragmento (normalmente 4 MB) y, a continuación, usa Content-Range y Content-Length como metadatos para la carga. El número total de llamadas API web es igual al número de fragmentos + 1.

Obtener múltiples elementos con paginación

Utiliza la función get para transmitir los resultados página por página. Puede limitar los resultados totales con $top y sugerir el tamaño por página con el page_size parámetro . El SDK establece internamente el encabezado de OData "prefer" 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})

Esta es una lista de parámetros admitidos donde todos son opcionales, excepto logical_name.

  • logical_name: str : nombre lógico (singular), por ejemplo, "cuenta".
  • select: list[str] | None — Columnas:> $select (separadas por comas).
  • filter: str | None: expresión de $filter OData (por ejemplo, contains(name,'Acme') y statecode eq 0).
  • orderby: list[str] | None — Expresiones de clasificación -> $orderby (separado por comas).
  • top: int | None - Límite global mediante $top (aplicado en la primera solicitud; el servicio lo aplica a través de las páginas).
  • expand: list[str] | None: expansiones de navegación:> $expand; pasar cláusulas sin formato (por ejemplo, primarycontactid($select=fullname,emailaddress1)).
  • page_size: int | Ninguno: sugerencia por página con Prefer: odata.maxpagesize=<N> (no garantizado; la última página puede ser más pequeña).

Esta es una lista de valores devueltos & semántica.

  • $select, $filter, $orderby, $expand, $top corresponden directamente con las opciones de consulta de OData correspondientes en la primera solicitud.
  • $top limita el número total de filas; el servicio puede particionar las filas en varias páginas.
  • page_size (Prefer: odata.maxpagesize) es una sugerencia; el servidor decide los límites de página reales.
  • Devuelve un generador que produce páginas no vacías (list[dict]). Se omiten las páginas vacías.
  • Cada lista de resultados corresponde a una página de valores de la API web.
  • La iteración se detiene cuando no queda @odata.nextLink (o cuando se cumple del lado del servidor con $top).
  • El generador no materializa todos los resultados; las páginas se capturan de forma diferida.

Veamos un ejemplo con todos los parámetros admitidos más la respuesta 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)})

Metadatos de la tabla

Echemos un vistazo al código de ejemplo para trabajar con una tabla 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)

Información adicional sobre cómo trabajar con metadatos de tabla personalizados:

  • create siempre devuelve una lista de GUID (length=1 para una sola entrada).
  • update y delete devuelven None para interfaces únicas y múltiples.
  • Pasar una lista de cargas para create desencadenar una creación masiva y devuelve una lista[str] de identificadores.
  • get admite la recuperación de registros únicos con identificador de registro o paginación a través de conjuntos de resultados (prefiere seleccionar para limitar columnas).
  • Para los métodos CRUD que toman un identificador de registro, pase la cadena GUID de 36 caracteres con guiones. Los paréntesis alrededor del GUID se aceptan, pero no son necesarios.
  • Las consultas SQL se ejecutan directamente en los puntos de conexión del conjunto de entidades mediante el parámetro ?sql=. Solo subconjunto admitido (SELECT único, opcional WHERE/TOP/ORDER BY, alias). El servicio rechaza las construcciones no admitidas.

Uso de Pandas con el SDK

PandasODataClient es una envoltura ligera alrededor del cliente de bajo nivel. Todos los métodos aceptan nombres lógicos (singulares) (por ejemplo, account, new_sampleitem), no se admiten nombres de conjunto de entidades (plural). Consulte el ejemplo del repositorio de origen del SDK denominado "quickstart_pandas.py" para un DataFrame flujo de trabajo.

Consulte también