Skip to main content

dv-metadata

Dataverse schema authoring and inspection — tables, columns, relationships, forms, and views. Use when the user wants to define, evolve, or inspect the data model — add a column, create a table, set up a lookup, customize a form, build a view, or list existing columns and relationships.

소스 정보

저장소
microsoft/Dataverse-skills
최근 소스 활동
2026년 10월 12일 18:29
감지된 SKILL.md 언어
영어
스타
249
포크
64

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
4 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
dv-metadata
description
Dataverse schema authoring and inspection — tables, columns, relationships, forms, and views. Use when the user wants to define, evolve, or inspect the data model — add a column, create a table, set up a lookup, customize a form, build a view, or list existing columns and relationships.
# Skill: Metadata — Making Changes **Before the first metadata change in a session:** 1. **Confirm the target environment** with the user — see the Multi-Environment Rule in dv-overview. 2. **Confirm the solution** — ask "What solution should these components go into?" If `SOLUTION_NAME` is in `.env`, confirm it. If no solution exists yet, **you MUST ask the user** for the solution name and publisher prefix before creating anything. The publisher prefix is **permanent** — it cannot be changed after components are created with it. **STOP and ask the user:** > "What solution name and publisher prefix should I use? The prefix (e.g., `contoso`, `lit`, `soc`) is permanent on every table and column." Then query existing publishers and show them — the user may want to reuse one: ```python # Publisher discovery + solution creation — use SDK (never raw Web API). # See dv-solution for the full publisher discovery flow. publishers = client.records.list("publisher", filter="customizationprefix ne 'none' and uniquename ne 'MicrosoftCorporation'", select=["publisherid", "uniquename", "friendlyname", "customizationprefix"], top=10) # MANDATORY: Show existing publishers to user and ask which to use or create new ``` After user confirms, create using SDK: ```python publisher_id = client.records.create("publisher", { "uniquename": "<name>", "friendlyname": "<display>", "customizationprefix": "<prefix>", # from user input, NOT hardcoded "description": "<desc>", }) solution_id = client.records.create("solution", { "uniquename": "<SolutionName>", "friendlyname": "<Display Name>", "version": "1.0.0.0", "publisherid@odata.bind": f"/publishers({publisher_id})", }) ``` Never create tables or columns outside a solution. 3. Pass `solution="<UniqueName>"` in every SDK call, or include `"MSCRM.SolutionName": "<UniqueName>"` on every raw Web API call. ## Skill boundaries | Need | Use instead | |---|---| | Create, update, or delete data records | **dv-data** | | Query or read records | **dv-query** | | Export or deploy solutions | **dv-solution** | | ERP schema | **dv-query**; [ERP routing](../dv-overview/references/erp-target.md) | --- ## How Changes Are Made: Environment-First **Do not write solution XML by hand to create new tables, columns, forms, or views.** The environment validates metadata far more reliably than an agent editing XML. The correct workflow is: 1. **Make the change in the environment** via the Dataverse MetadataService API (or `pac` commands where available) 2. **Pull the change into the repo** via `pac solution export` + `pac solution unpack` 3. **Commit the result** The exported XML is generated by Dataverse itself and is always valid. Hand-written XML is fragile — a single incorrect attribute or missing element causes an import failure with an opaque error. The only time you write files directly is when editing something that already exists in the repo (e.g., tweaking an existing view's columns or modifying a form layout you've already pulled). **CLI schema inspection:** `dataverse data describe --table account --include all --json` (uses LogicalName). API discovery: `dataverse api list --target dataverse`. --- ## Creating a Table **If creating multiple tables for a data import**, also see these sections later in this skill: - **Idempotent Table Creation** — check-first pattern for re-runnable scripts - **Alternate Keys** — required for upsert; create immediately after each table - **Metadata Propagation Delays and Lock Contention** — phased creation to avoid lock errors **Prefer the SDK for table creation** — use raw Web API only when you need full control over OwnershipType, HasActivities, or other advanced properties the SDK doesn't expose. **SDK approach (use this by default):** ```python 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-metadata") info = client.tables.create( "new_ProjectBudget", {"new_Amount": "decimal", "new_Description": "string"}, solution="MySolution", primary_column="new_Name", display_name="Project Budget", # human-readable name; plural auto-appends "s" ) print(f"Created: {info['table_schema_name']}") ``` **Web API fallback (ONLY when you need OwnershipType, HasActivities, or other properties the SDK doesn't expose):** ```python # Helper for Label boilerplate def label(text): return {"@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [{"@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": text, "LanguageCode": 1033}]} entity = { "@odata.type": "Microsoft.Dynamics.CRM.EntityMetadata", "SchemaName": "new_ProjectBudget", "DisplayName": label("Project Budget"), "DisplayCollectionName": label("Project Budgets"), "Description": label(""), "OwnershipType": "UserOwned", "HasActivities": False, "HasNotes": False, "IsActivity": False, "PrimaryNameAttribute": "new_name", "Attributes": [{ "@odata.type": "Microsoft.Dynamics.CRM.StringAttributeMetadata", "SchemaName": "new_name", "DisplayName": label("Name"), "RequiredLevel": {"Value": "ApplicationRequired"}, "MaxLength": 100, "IsPrimaryName": True, }] } # POST to /api/data/v9.2/EntityDefinitions with MSCRM.SolutionUniqueName header ``` --- ## Column Naming: Avoid `*Id` Suffix Collisions **Never name a regular column with an `Id` suffix** (e.g., `prefix_CountryId`). Dataverse auto-generates a navigation property with the `Id` suffix when you create a lookup — if a regular column with that name exists, lookup creation fails with a schema name collision. - WRONG: `prefix_DepartmentId` (int) — collides with auto-generated lookup - RIGHT: `prefix_SrcDepartmentId` or `prefix_DepartmentSourceId` --- ## Adding Columns **SDK approach (preferred):** ```python created = client.tables.add_columns( "new_ProjectBudget", {"new_Description": "string", "new_Amount": "decimal", "new_Active": "bool"}, ) print(created) # ['new_Description', 'new_Amount', 'new_Active'] ``` Supported type strings: `"string"` / `"text"`, `"int"` / `"integer"`, `"decimal"` / `"money"`, `"float"` / `"double"`, `"datetime"` / `"date"`, `"bool"` / `"boolean"`, `"file"`, and `Enum` subclasses (for local option sets). **Choice (picklist) column via SDK:** ```python from enum import IntEnum class BudgetStatus(IntEnum): DRAFT = 100000000 APPROVED = 100000001 REJECTED = 100000002 created = client.tables.add_columns( "new_ProjectBudget", {"new_Status": BudgetStatus}, ) ``` **Set constraints — pass a dict spec** instead of a bare type string (keys: `max_length`, `min_value`, `max_value`, `precision`, `format`, `required`, `display_name`); works on `create` and `add_columns`, no raw Web API: ```python client.tables.add_columns("new_ProjectBudget", { "new_Amount": {"type": "money", "min_value": 0, "max_value": 1000000000, "precision": 2}, "new_Comment": {"type": "memo", "max_length": 2000, "display_name": "Comment"}, }) ``` Change an existing column in place with `update_column(table, col, spec)` or `update_columns(table, {col: spec})` — same keys; all specs are validated before any write. --- ## Lookup Columns and Relationships **SDK approach — simple lookup (preferred):** ```python result = client.tables.create_lookup_field( referencing_table="new_projectbudget", lookup_field_name="new_AccountId", referenced_table="account", display_name="Account", solution="MySolution", ) print(f"Created lookup: {result.lookup_schema_name}") ``` **SDK approach — full control over 1:N relationship:** ```python from PowerPlatform.Dataverse.models.relationship import ( LookupAttributeMetadata, OneToManyRelationshipMetadata, CascadeConfiguration, ) from PowerPlatform.Dataverse.models.labels import Label, LocalizedLabel from PowerPlatform.Dataverse.common.constants import CASCADE_BEHAVIOR_REMOVE_LINK lookup = LookupAttributeMetadata( schema_name="new_AccountId", display_name=Label(localized_labels=[LocalizedLabel(label="Account", language_code=1033)]), ) relationship = OneToManyRelationshipMetadata( schema_name="account_new_projectbudget", referenced_entity="account", referencing_entity="new_projectbudget", referenced_attribute="accountid", cascade_configuration=CascadeConfiguration(delete=CASCADE_BEHAVIOR_REMOVE_LINK), ) result = client.tables.create_one_to_many_relationship(lookup, relationship, solution="MySolution") print(f"Created: {result.relationship_schema_name}") ``` **SDK approach — many-to-many relationship:** ```python from PowerPlatform.Dataverse.models.relationship import ManyToManyRelationshipMetadata relationship = ManyToManyRelationshipMetadata( schema_name="new_ticket_knowledgebase", entity1_logical_name="new_ticket", entity2_logical_name="new_knowledgebase", ) result = client.tables.create_many_to_many_relationship(relationship, solution="MySolution") print(f"Created: {result.relationship_schema_name}") ``` **Web API approach (fallback when SDK patterns don't suffice):** ```python relationship = { "@odata.type": "Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata", "SchemaName": "account_new_projectbudget", "ReferencedEntity": "account", "ReferencingEntity": "new_projectbudget", "Lookup": { "@odata.type": "Microsoft.Dynamics.CRM.LookupAttributeMetadata", "SchemaName": "new_AccountId", "DisplayName": {"@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [{"@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Account", "LanguageCode": 1033}]}, "RequiredLevel": {"Value": "None"} } } # POST to /api/data/v9.2/RelationshipDefinitions ``` **After creating a lookup — the @odata.bind navigation property:** When you create records that set this lookup, you need the **navigation property name** for `@odata.bind`. The navigation property name is case-sensitive and must match the entity's `$metadata` (usually the SchemaName of the lookup field, e.g., `new_AccountId`): | Navigation Property Name | `@odata.bind` key | Entity set | |---|---|---| | `new_AccountId` | `new_AccountId@odata.bind` | `/accounts(<guid>)` | | `new_ParentTicketId` | `new_ParentTicketId@odata.bind` | `/new_tickets(<guid>)` | **Common mistake:** Using the logical name (lowercase) like `new_accountid@odata.bind` returns a 400 error. Navigation property names are case-sensitive and must match the entity's `$metadata`. --- ## Adding a Table to a Solution After creating a table via API, add it to your solution so it gets pulled on export: ``` pac solution add-solution-component \ --solutionUniqueName <SOLUTION_NAME> \ --component <SchemaName> \ --componentType 1 \ --environment <url> ``` Component type `1` = Entity (Table). See dv-solution for the full type code list. Or via Web API: ```python # POST to /api/data/v9.2/AddSolutionComponent body = { "ComponentId": "<entity-metadata-id>", "ComponentType": 1, # 1 = Entity "SolutionUniqueName": "<SOLUTION_NAME>", "AddRequiredComponents": True } ``` --- ## Forms and Views `systemform` (forms) and `savedquery` (views) are **ordinary entities** — create/read/modify them with the **SDK's record CRUD** (no `urllib`). Only **publishing** (`PublishXml`, an unbound action) needs `dataverse api request`. **Quick reference:**
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기