dv-data

โดย microsoft

การดำเนินการ CRUD ระดับเรกคอร์ดและการทำงานแบบกลุ่มผ่าน Python SDK — สร้าง, อัปเดต, ลบ, อัปเซิร์ต, นำเข้า CSV, โหลดคีย์ต่างประเทศหลายตาราง, ข้อมูลตัวอย่างที่สร้างโดย AI…

npx skills add https://github.com/microsoft/dataverse-skills --skill dv-data

Skill: Data — Create, Update, Delete, and Bulk Import

This skill uses Python exclusively. Do not use Node.js, JavaScript, or any other language for Dataverse scripting. If you are about to run npm install or write a .js file, STOP — you are going off-rails. See the overview skill's Hard Rules.

Use the official Microsoft Power Platform Dataverse Client Python SDK for all data write operations.

Official SDK: https://github.com/microsoft/PowerPlatform-DataverseClient-Python PyPI package: PowerPlatform-Dataverse-Client (this is the only official one — do not use dataverse-api or other unofficial packages) Status: Preview — breaking changes are possible

Skill boundaries

NeedUse instead
Query or read recordsdv-query
Create tables, columns, relationships, forms, viewsdv-metadata
Export or deploy solutionsdv-solution

Before Writing ANY Script — Check MCP First

If MCP tools are available (create_record, update_record) and the task is ≤10 records, use MCP directly — no script needed. Only write a Python script when the task requires: bulk operations (10+ records), data transformation, retry logic, CSV import, or operations the SDK supports that MCP cannot (upsert, file uploads). Sequential MCP tool calls are not "multi-step logic" — use MCP for those.

SDK-First Rule

If an operation is in the "supports" list below, you MUST use the SDK — not urllib, requests, or raw HTTP.

Correct import (always preceded by sys.path.insert in a full script — see Setup below):

from auth import get_client

WRONG for SDK-supported operations:

from auth import get_token, load_env  # WRONG for SDK-supported ops
import requests                        # WRONG for SDK-supported ops

get_token() and requests exist ONLY for operations the SDK does not support (forms, views, $apply, N:N $expand, unbound actions) — see dv-query and dv-metadata.


What This SDK Supports (Data Operations)

  • Record writes: create, update, delete
  • Record reads within write workflows (e.g., lookup resolution) — for standalone queries see dv-query
  • Upsert (with alternate key support)
  • Bulk operations: CreateMultiple, UpdateMultiple, UpsertMultiple
  • File column uploads (chunked for files >128MB)
  • Context manager with HTTP connection pooling

What This SDK Does NOT Support

Use raw Web API (get_token()) for:

  • Forms (FormXml) — see dv-metadata
  • Views (SavedQueries) — see dv-metadata
  • Global option sets — see dv-metadata
  • N:N record association ($ref POST) — use raw Web API (POST /api/data/v9.2/<entity>(<id>)/<nav-property>/$ref)
  • N:N $expand — see dv-query
  • $apply aggregation — see dv-query
  • Unbound actions (e.g., InstallSampleData)
  • DeleteMultiple, general OData batching

Setup

import os, sys
sys.path.insert(0, os.path.join(os.getcwd(), "scripts"))
from auth import get_client

# get_client sets a plugin attribution context on the User-Agent header.
# Do not modify the context value — it is a closed schema for server-side
# telemetry (app/skill/agent). Never include secrets or PII.
client = get_client("dv-data")

get_client(skill) handles auth, environment URL, and plugin attribution (User-Agent tagging). See scripts/auth.py.

For scripts that run to completion: wrap in with DataverseClient(...) as client: for automatic connection cleanup (recommended since b6). For notebooks and interactive sessions, the explicit client above is simpler.


Field Name Casing Rule

Getting this wrong causes 400 errors.

Property typeConventionExampleWhen used
Structural (columns)LogicalName — always lowercasenew_name, new_priorityRecord payload keys
Navigation (lookups)Navigation Property Name — case-sensitive, matches $metadatanew_AccountId@odata.bind keys

The SDK lowercases structural keys automatically but preserves @odata.bind key casing.


Create a Record

guid = client.records.create("new_ticket", {
    "new_name": "Ticket 001",
    "new_priority": 100000002,          # choice column — integer value, not string
    "[email protected]": "/accounts(<account-guid>)",
})
print(f"Created: {guid}")

@odata.bind notes:

  • Key is the Navigation Property Name: [email protected] (the SDK preserves casing automatically as of b6, but matching the schema name is still the correct form)
  • Value is "/<EntitySetName>(<guid>)" — e.g., "/accounts(<guid>)"
  • If you just created the lookup column, wait 5–10 seconds before inserting. Metadata propagation delays cause "Invalid property" errors.
  • Choice columns use integer values, not strings: "new_priority": 100000002 (not "High")

Common @odata.bind patterns

LookupCorrect keyWrong
Custom: new_AccountId[email protected][email protected]
System polymorphic: customerid[email protected][email protected]
System: parentcustomerid[email protected][email protected]

Find the Navigation Property Name

After creating a lookup via SDK: result.lookup_schema_name is the navigation property name.

For existing system tables, query:

GET /api/data/v9.2/EntityDefinitions(LogicalName='<entity>')/ManyToOneRelationships
  ?$select=ReferencingEntityNavigationPropertyName,ReferencedEntity

Update a Record

client.records.update("new_ticket", "<record-guid>",
    {"new_status": 100000001})

Delete a Record

client.records.delete("new_ticket", "<record-guid>")

Bulk Create (SDK uses CreateMultiple internally)

records = [{"new_name": f"Ticket {i}", "new_priority": 100000000} for i in range(500)]
guids = client.records.create("new_ticket", records)
print(f"Created {len(guids)} records")

Volume guidance: MCP create_record for 1-10 records. SDK for 10+ records.

Important: The SDK sends all records in a single POST to CreateMultiple. It does not chunk automatically. Dataverse has no fixed record count limit — the constraints are payload size and request timeout (SDK default: 120s for POST). For larger datasets, you must chunk in your script. The bulk_upsert and bulk_create helpers below use adaptive chunking: start at 1,000, double on success (up to 4,000), halve on payload/timeout failure, and cap at the last successful size. Tables with few columns can handle larger chunks than tables with many columns.


Bulk Update

# Broadcast same change to multiple records
client.records.update("new_ticket",
    [id1, id2, id3],
    {"new_status": 100000001})

DataFrame Write-Back

To create or update records from a pandas DataFrame, use the client.dataframe namespace. This is documented in dv-query (alongside client.dataframe.get()) but is a write operation — include it in your data write workflow:

# Update records — DataFrame must include the primary key column
client.dataframe.update("opportunity", df_updates, id_column="opportunityid")

# Create records — returns a Series of new GUIDs
guids = client.dataframe.create("opportunity", df_new_records)

See dv-query for the full client.dataframe reference including client.dataframe.get().


Upsert (Alternate Keys)

Idempotent — re-running the same import does not create duplicates. The alternate key must be defined on the table first — see dv-metadata.

Do NOT include alternate key columns in the record body. The alternate key identifies the record; the record body contains the data to set. If the same column appears in both, UpsertMultiple fails with "An unexpected error occurred" (single upsert tolerates it, bulk does not).

from PowerPlatform.Dataverse.models.upsert import UpsertItem

client.records.upsert("account", [
    UpsertItem(
        alternate_key={"accountnumber": "ACC-001"},
        record={"name": "Contoso Ltd", "description": "Primary account"},
    ),
    UpsertItem(
        alternate_key={"accountnumber": "ACC-002"},
        record={"name": "Fabrikam Inc"},
    ),
])

Bulk Import from CSV

For imports that may be re-run (most real-world cases), use UpsertItem with alternate keys instead of create() — see references/multi-table-fk-import.md. The create() pattern here is for one-shot loads only.

VolumeToolWhy
1–10 recordsMCP create_recordSimple, no script
10+ recordsSDK client.records.create(table, list)Uses CreateMultiple; chunk large datasets (start at 1K, adapt)
import csv, os, sys
sys.path.insert(0, os.path.join(os.getcwd(), "scripts"))
from auth import get_client

# get_client sets a plugin attribution context on the User-Agent header.
# Do not modify the context value — it is a closed schema for server-side
# telemetry (app/skill/agent). Never include secrets or PII.
client = get_client("dv-data")

with open("data/customers.csv", newline="", encoding="utf-8") as f:
    rows = list(csv.DictReader(f))

records = [{"new_name": row["name"], "new_email": row["email"]} for row in rows]

# SDK sends all in one POST — chunk to avoid payload/timeout limits
# Start at 1000; for narrow tables (few columns) you can go higher
chunk_size = 1000
for i in range(0, len(records), chunk_size):
    guids = client.records.create("new_customer", records[i:i + chunk_size])
    print(f"Imported {i + len(guids)}/{len(records)} customers", flush=True)

Lookup resolution during import

If the CSV has a human-readable key (e.g., customer_email) but Dataverse needs a GUID, pre-resolve with a lookup dict:

# Build email -> GUID map first
email_to_guid = {}
for page in client.records.get("new_customer", select=["new_customerid", "new_email"]):
    for r in page:
        email_to_guid[r["new_email"]] = r["new_customerid"]

# Use it during import
records = []
for row in rows:
    customer_guid = email_to_guid.get(row["customer_email"])
    if not customer_guid:
        print(f"Skipping row — unknown email: {row['customer_email']}")
        continue
    records.append({
        "new_channel": row["channel"],
        "[email protected]": f"/new_customers({customer_guid})",  # verify entity set name via EntityDefinitions
    })

guids = client.records.create("new_interaction", records)

Required field discovery for system tables

Before bulk-creating in a system table (account, contact, opportunity):

  1. Create a single test record with your intended minimal payload
  2. If HttpError 400 is raised, the error message names the missing required field
  3. Some required fields are plugin-enforced and not visible in describe_table
  4. Delete the test record, then proceed with bulk create

Multi-Table Import with FK Dependencies

When importing data across multiple tables with foreign key relationships, the import must run in dependency order with UpsertItem + alternate keys (idempotent, safe for re-runs).

Quick reference:

  1. Create tables with source ID columns + alternate keys + lookup relationships (see dv-metadata).
  2. Import Level 0 (no FK deps) tables in parallel via ThreadPoolExecutor. Sequential chunks within each table (concurrent writes deadlock).
  3. Build source-ID → GUID maps by querying back (upsert doesn't return GUIDs).
  4. Repeat per dependency level — Level 1 needs Level 0's maps for @odata.bind.

For the full pattern — adaptive bulk_upsert helper, composite-key handling, post-import verification, and the first-time bulk_create variant — see references/multi-table-fk-import.md.

Key invariants (apply even without reading the reference):

  • Parallelize across tables at the same level, sequential between levels, sequential chunks within a table.
  • Alternate key columns must NOT also appear in the record bodyUpsertMultiple fails.
  • Catch per-table failures in the executor — one table failing must not kill the others.
  • Start chunk_size=1000; the helper ramps up adaptively.

Error Handling

from PowerPlatform.Dataverse.core.errors import HttpError

try:
    guid = client.records.create("new_ticket", {"new_name": "Test"})
except HttpError as e:
    print(f"Status {e.status_code}: {e.message}")
    if e.details:
        print(f"Details: {e.details}")
    # 400 — bad field name, @odata.bind format, or missing required field
    # 403 — check security roles
    # 404 — table or record not found
    # 429 — rate limited; SDK retries automatically, reduce batch size if persistent

Windows Scripting Notes

  • ASCII only in .py files — curly quotes and em dashes cause SyntaxError on Windows.
  • No python -c for multiline code — write a .py file instead.
  • Generate GUIDs in scripts: str(uuid.uuid4()), not shell backtick substitution.

Sample Data Generation

Generate realistic sample records inline — schema-driven, table-agnostic, PII-safe defaults (@example.com emails, 555-01xx phones).

Quick reference: confirm environment + count + table → query EntityDefinitions(LogicalName='<table>')/Attributes?$filter=AttributeOf eq null for required columns → dispatch by AttributeType (String / Memo / Integer / DateTime / Picklist / etc.) → client.records.create() (use CreateMultiple for count >= 10).

For the schema-driven fake() template, the EntityDefinitions query, and the safety rules, see references/sample-data-generation.md.

Key invariants:

  • Skip Lookup, Uniqueidentifier, State, Status, Owner, Customer fields unless the user explicitly provides values.
  • UserLocalizedLabel may be null — dereference safely.

Confirmation-flow examples

Generate N sample records (destructive — preview the snippet, ask for env):

  • ❌ "Which environment should I target? Please provide the Dataverse URL."
  • ✅ "I'll run the Sample Data Generation snippets with TABLE=\"contact\", COUNT=20. Uses CreateMultiple, .example.com emails, 555-01xx phones, against the active pac auth list environment. Confirm to proceed, or specify a different environment."

Sample data on a custom entity (schema unknown — prose is enough):

  • ❌ "I need more info about the entity. What are the required fields?"
  • ✅ "Custom entity — I'll query EntityDefinitions for cr123_project to discover required columns, then generate 5 records inline mapping each column to a generator by AttributeType and call client.records.create(\"cr123_project\", records). Confirm to proceed, or tell me a different count."

Skills เพิ่มเติมจาก microsoft

oss-growth
microsoft
บุคลิกภาพนักเติบโตโอเอสเอส
official
microsoft-foundry
microsoft
ปรับใช้ ประเมิน และจัดการ Foundry agents แบบครบวงจร: สร้าง Docker, push ไปยัง ACR, สร้าง hosted/prompt agent, เริ่ม container, batch eval, continuous eval, เวิร์กโฟลว์ prompt optimizer, agent.yaml, จัดชุดข้อมูลจาก traces ใช้สำหรับ: ปรับใช้ agent ไปยัง Foundry, hosted agent, สร้าง agent, เรียกใช้ agent, ประเมิน agent, รัน batch eval, continuous eval, การตรวจสอบต่อเนื่อง, สถานะ continuous eval, ปรับแต่ง prompt, ปรับปรุง prompt, prompt optimizer, ปรับแต่งคำแนะนำ agent, ปรับปรุง agent...
officialdevelopmentdevops
azure-ai
microsoft
ใช้สำหรับ Azure AI: ค้นหา, คำพูด, OpenAI, การประมวลผลเอกสารอัจฉริยะ ช่วยในการค้นหา, การค้นหาแบบเวกเตอร์/ไฮบริด, การแปลงคำพูดเป็นข้อความ, การแปลงข้อความเป็นคำพูด, การถอดเสียง, OCR เมื่อ: การค้นหา AI, การค้นหาคำถาม, การค้นหาแบบเวกเตอร์, การค้นหาแบบไฮบริด, การค้นหาเชิงความหมาย, การแปลงคำพูดเป็นข้อความ, การแปลงข้อความเป็นคำพูด, การถอดเสียง, OCR, แปลงข้อความเป็นคำพูด
officialdevelopmentapi
azure-deploy
microsoft
ดำเนินการปรับใช้ Azure สำหรับแอปพลิเคชันที่เตรียมไว้แล้วซึ่งมีไฟล์ .azure/deployment-plan.md และไฟล์โครงสร้างพื้นฐานอยู่แล้ว ห้ามใช้ทักษะนี้เมื่อผู้ใช้ขอสร้างแอปพลิเคชันใหม่ ให้ใช้ azure-prepare แทน ทักษะนี้รันคำสั่ง azd up, azd deploy, terraform apply และ az deployment พร้อมการกู้คืนข้อผิดพลาดในตัว ต้องมี .azure/deployment-plan.md จาก azure-prepare และสถานะที่ตรวจสอบแล้วจาก azure-validate เมื่อ: "run azd up", "run azd deploy", "execute deployment",...
officialdevopsaws
azure-storage
microsoft
บริการ Azure Storage รวมถึง Blob Storage, File Shares, Queue Storage, Table Storage และ Data Lake ตอบคำถามเกี่ยวกับระดับการเข้าถึงพื้นที่จัดเก็บ (hot, cool, cold, archive) ว่าเมื่อใดควรใช้แต่ละระดับ และการเปรียบเทียบระดับ ให้บริการจัดเก็บวัตถุ, แชร์ไฟล์ SMB, การส่งข้อความแบบอะซิงโครนัส, NoSQL key-value และการวิเคราะห์ข้อมูลขนาดใหญ่ รวมถึงการจัดการวงจรชีวิต ใช้สำหรับ: blob storage, file shares, queue storage, table storage, data lake, อัปโหลดไฟล์, ดาวน์โหลด blobs, storage accounts, access tiers,...
officialdevelopmentdatabase
azure-diagnostics
microsoft
ดีบักปัญหาการผลิตบน Azure โดยใช้ AppLens, Azure Monitor, สถานะทรัพยากร และการจัดลำดับความสำคัญอย่างปลอดภัย เมื่อ: ดีบักปัญหาการผลิต, แก้ไขปัญหาแอปบริการ, แอปบริการ CPU สูง, แอปบริการล้มเหลวในการปรับใช้, แก้ไขปัญหาคอนเทนเนอร์แอป, แก้ไขปัญหาฟังก์ชัน, แก้ไขปัญหา AKS, kubectl ไม่สามารถเชื่อมต่อ, kube-system/CoreDNS ล้มเหลว, pod รอ, crashloop, node ไม่พร้อม, การอัปเกรดล้มเหลว, วิเคราะห์บันทึก, KQL, ข้อมูลเชิงลึก, การดึงอิมเมจล้มเหลว, ปัญหาการเริ่มต้นเย็น, การตรวจสอบสถานะล้มเหลว,...
officialdevopsdevelopment
azure-prepare
microsoft
เตรียมแอปพลิเคชัน Azure สำหรับการปรับใช้ (infra Bicep/Terraform, azure.yaml, Dockerfiles) ใช้สำหรับสร้าง/ปรับปรุงให้ทันสมัย หรือสร้าง+ปรับใช้ ไม่ใช่สำหรับการย้ายข้ามคลาวด์ (ใช้ azure-cloud-migrate) ห้ามใช้สำหรับ: แอป copilot-sdk (ใช้ azure-hosted-copilot-sdk) เมื่อ: "สร้างแอป", "สร้างเว็บแอป", "สร้าง API", "สร้าง HTTP API แบบไร้เซิร์ฟเวอร์", "สร้างฟรอนต์เอนด์", "สร้างแบ็กเอนด์", "สร้างบริการ", "ปรับปรุงแอปพลิเคชันให้ทันสมัย", "อัปเดตแอปพลิเคชัน", "เพิ่มการรับรองความถูกต้อง", "เพิ่มการแคช", "โฮสต์บน Azure", "สร้างและ...
officialdevelopmentdevops
azure-validate
microsoft
การตรวจสอบความพร้อมก่อนการปรับใช้สำหรับ Azure ตรวจสอบเชิงลึกเกี่ยวกับการกำหนดค่า โครงสร้างพื้นฐาน (Bicep หรือ Terraform) การกำหนดบทบาท RBAC สิทธิ์ของ managed identity และข้อกำหนดเบื้องต้นก่อนการปรับใช้ เมื่อ: ตรวจสอบแอปของฉัน ตรวจสอบความพร้อมในการปรับใช้ เรียกใช้การตรวจสอบก่อนดำเนินการ ยืนยันการกำหนดค่า ตรวจสอบว่าพร้อมปรับใช้หรือไม่ ตรวจสอบ azure.yaml ตรวจสอบ Bicep ทดสอบก่อนปรับใช้ แก้ไขข้อผิดพลาดในการปรับใช้ ตรวจสอบ Azure Functions ตรวจสอบ function app ตรวจสอบ serverless...
officialdevopstesting