Dataverse Web API — práce s metadaty (Deep Research)

Zdroj: oficiální Microsoft Learn dokumentace pro Dynamics 365 / Microsoft Dataverse Web API v9.2. Cílem dokumentu je být referenční příručkou pro typický workflow: zjistit, zda něco existuje → stáhnout metadata → doplnit chybějící prvky → propagovat do solution → publikovat.


1. Základní koncepty

Dataverse Web API je RESTful endpoint, který kromě běžných datových operací umožňuje kompletní správu schématu (metadat) — tabulek (entit), sloupců (atributů), vztahů a globálních choices (optionsetů).

1.1 Endpoint pro metadata

Web API vystavuje čtyři hlavní entity sety pro práci se schématem:

Entity Set Path Obsah
/api/data/v9.2/EntityDefinitions Kolekce EntityMetadata (tabulky)
/api/data/v9.2/RelationshipDefinitions OneToManyRelationshipMetadata a ManyToManyRelationshipMetadata (oboje dědí z RelationshipMetadataBase)
/api/data/v9.2/GlobalOptionSetDefinitions Globální choices — OptionSetMetadata a BooleanOptionSetMetadata
/api/data/v9.2/ManagedPropertyDefinitions Pouze pro interní použití

Sloupce (atributy) nejsou samostatný entity set — pracuje se s nimi přes navigation property Attributes v kontextu tabulky:

/api/data/v9.2/EntityDefinitions(LogicalName='account')/Attributes

1.2 Klíčové vlastnosti všech metadat

1.3 CSDL $metadata dokument

Pro úplnou definici celého schématu prostředí použijte:

GET https://yourorg.api.crm.dynamics.com/api/data/v9.2/$metadata

S anotacemi (description, computed, permissions):

GET https://yourorg.api.crm.dynamics.com/api/data/v9.2/$metadata?annotations=true

Tento XML dokument je zdroj pravdy pro všechny EntityType, Action, Function, ComplexType a EnumType ve vašem prostředí. Názvy jsou case-sensitive.

1.4 HTTP metody pro schéma

Operace Metoda Poznámka
Read GET
Create POST Endpoint vrací URI nového objektu v hlavičce OData-EntityId
Update PUT (NE PATCH) Nahrazuje celou definici — musíte poslat všechny vlastnosti, které nechcete změnit
Delete DELETE

⚠️ Schémové entity nepodporují PATCH. Vždy PUT s kompletní definicí — to je zásadní rozdíl oproti business datům.

1.5 Důležité hlavičky

Hlavička Účel
MSCRM.SolutionUniqueName Přidá vytvářený/aktualizovaný prvek do uvedené solution
MSCRM.MergeLabels: true Při update zachová existující lokalizované labely v jazycích, které nepřepisujete
Consistency: Strong Doporučeno pro čtení metadat
OData-MaxVersion: 4.0, OData-Version: 4.0 Povinné

2. Stažení metadat — různé typy dotazů

2.1 Retrieve podle alternativního klíče (nejrychlejší)

Definiční prvek Alternativní klíč Příklad
Tabulka LogicalName GET /api/data/v9.2/EntityDefinitions(LogicalName='account')
Sloupec LogicalName GET /api/data/v9.2/EntityDefinitions(LogicalName='account')/Attributes(LogicalName='emailaddress1')
Vztah SchemaName GET /api/data/v9.2/RelationshipDefinitions(SchemaName='Account_Tasks')
Global Choice Name GET /api/data/v9.2/GlobalOptionSetDefinitions(Name='metric_goaltype')

2.2 Retrieve podle MetadataId (primární klíč)

GET /api/data/v9.2/EntityDefinitions(70816501-edb9-4740-a16c-6a5efbc05d84)
GET /api/data/v9.2/EntityDefinitions(<EntityId>)/Attributes(<AttributeId>)

2.3 Selektivní stažení (vždy používejte $select)

EntityMetadata je velmi rozsáhlá entita — bez $select dostanete obrovský payload. Příklad:

GET /api/data/v9.2/EntityDefinitions(LogicalName='account')
    ?$select=DisplayName,IsKnowledgeManagementEnabled,EntitySetName
Accept: application/json
OData-MaxVersion: 4.0
OData-Version: 4.0

MetadataId je vrácen vždy, bez ohledu na $select.

2.4 Expand atributů s castováním na konkrétní typ

Atributy obsahují polymorfní typy. Pokud potřebujete vlastnosti specifické pro daný typ (např. OptionSet u picklistu, Precision u money), musíte castovat:

GET /api/data/v9.2/EntityDefinitions(LogicalName='account')/Attributes/Microsoft.Dynamics.CRM.PicklistAttributeMetadata
    ?$select=LogicalName
    &$expand=OptionSet,GlobalOptionSet

Filtrování atributů podle typu v expandu:

GET /api/data/v9.2/EntityDefinitions(LogicalName='account')
    ?$select=LogicalName
    &$expand=Attributes($select=LogicalName;$filter=AttributeType eq Microsoft.Dynamics.CRM.AttributeTypeCode'Picklist')

2.5 Filtrování přes komplexní vlastnosti

RequiredLevel je komplexní typ — pro filtrování použijte tečkovou notaci a enum:

GET /api/data/v9.2/EntityDefinitions(LogicalName='account')/Attributes
    ?$select=SchemaName
    &$filter=RequiredLevel/Value eq Microsoft.Dynamics.CRM.AttributeRequiredLevel'ApplicationRequired'

2.6 Získání optionset hodnot pro Picklist

GET /api/data/v9.2/EntityDefinitions(LogicalName='account')
    /Attributes(LogicalName='accountcategorycode')
    /Microsoft.Dynamics.CRM.PicklistAttributeMetadata
    ?$select=LogicalName
    &$expand=OptionSet($select=Options),GlobalOptionSet($select=Options)

Pokud používá lokální optionset, GlobalOptionSet bude null, a naopak. Proto je dobré expandovat oba a vyhodnotit, který je naplněn.

2.7 Žádný paging

Pozor — dotazy na metadata nemají stránkování. Vrátí všechno najednou. Proto vždy filtrujte a selektujte.

2.8 Mass retrieve přes RetrieveMetadataChanges

Pro velký objem metadat nebo pro inkrementální synchronizaci existuje funkce RetrieveMetadataChanges. Vrací ServerVersionStamp, který lze v dalším volání předat jako ClientVersionStamp — server pak vrátí jen změny od minulého stažení (včetně DeletedMetadata).


3. Typický workflow — „Check & Create“

Toto je hlavní use case dotazu. Skládá se ze dvou rozhodovacích bodů: (A) existuje tabulka? a (B) existuje na ní daný atribut?.

3.1 Strategie pro „existuje?“ check

Existují dva přístupy:

Přístup 1 — HTTP status code Pošlete GET s alternativním klíčem a očekávejte: - 200 OK → existuje (a v body máte rovnou metadata) - 404 Not Found → neexistuje

GET /api/data/v9.2/EntityDefinitions(LogicalName='new_bankaccount')?$select=MetadataId,LogicalName

Přístup 2 — filter query, kontrola počtu výsledků

GET /api/data/v9.2/EntityDefinitions
    ?$select=MetadataId,LogicalName
    &$filter=LogicalName eq 'new_bankaccount'

Vrátí 200 OK vždy; v value je pole 0 nebo 1 prvek. Vhodné, pokud nechcete řešit výjimky.

3.2 Pseudokód celého workflow

1. GET EntityDefinitions(LogicalName='new_bankaccount')?$select=MetadataId
   ├─ 200 → tabulka existuje, máš MetadataId
   └─ 404 → POST EntityDefinitions { ...full definition with primary name attribute... }
                 použij hlavičku MSCRM.SolutionUniqueName: <yourSolution>

2. GET EntityDefinitions(LogicalName='new_bankaccount')/Attributes(LogicalName='new_iban')?$select=MetadataId
   ├─ 200 → atribut existuje, případně PUT pro update
   └─ 404 → POST EntityDefinitions(LogicalName='new_bankaccount')/Attributes
                 { ...definition of new attribute with @odata.type... }
                 použij hlavičku MSCRM.SolutionUniqueName: <yourSolution>

3. POST PublishXml { "ParameterXml": "<importexportxml><entities><entity>new_bankaccount</entity></entities></importexportxml>" }

3.3 Klíčové pravidlo pro solution

Když na POST/PUT/DELETE pošlete hlavičku MSCRM.SolutionUniqueName: <unique_name>: - Komponenta je vytvořena/aktualizována primárně v default solution, - a zároveň je přidána do uvedené unmanaged solution.

Tím jednou request pokryjete oba kroky (create + addToSolution). To je doporučený způsob — bez nutnosti samostatného volání AddSolutionComponent.


4. Vytváření tabulky (EntityDefinitions)

4.1 Povinné vlastnosti

Tabulka musí mít definovaný primární name atribut v poli Attributes (přesně jeden StringAttributeMetadata s IsPrimaryName: true).

EntityMetadata property Hodnota
SchemaName např. new_BankAccount — používejte prefix vašeho publishera
DisplayName Label (lokalizovaný)
DisplayCollectionName Plural label
Description Popis (doporučeno)
OwnershipType UserOwned nebo OrganizationOwned
IsActivity true/false
HasActivities true/false
HasNotes true/false

4.2 Plný příklad POST

POST [Organization URI]/api/data/v9.2/EntityDefinitions HTTP/1.1
MSCRM.SolutionUniqueName: examplesolution
Accept: application/json
Content-Type: application/json; charset=utf-8
OData-MaxVersion: 4.0
OData-Version: 4.0

{
  "@odata.type": "Microsoft.Dynamics.CRM.EntityMetadata",
  "SchemaName": "new_BankAccount",
  "OwnershipType": "UserOwned",
  "IsActivity": false,
  "HasActivities": false,
  "HasNotes": false,
  "DisplayName": {
    "@odata.type": "Microsoft.Dynamics.CRM.Label",
    "LocalizedLabels": [
      {
        "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel",
        "Label": "Bank Account",
        "LanguageCode": 1033
      }
    ]
  },
  "DisplayCollectionName": {
    "@odata.type": "Microsoft.Dynamics.CRM.Label",
    "LocalizedLabels": [
      {
        "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel",
        "Label": "Bank Accounts",
        "LanguageCode": 1033
      }
    ]
  },
  "Description": {
    "@odata.type": "Microsoft.Dynamics.CRM.Label",
    "LocalizedLabels": [
      {
        "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel",
        "Label": "An entity to store information about customer bank accounts",
        "LanguageCode": 1033
      }
    ]
  },
  "Attributes": [
    {
      "@odata.type": "Microsoft.Dynamics.CRM.StringAttributeMetadata",
      "AttributeType": "String",
      "AttributeTypeName": { "Value": "StringType" },
      "SchemaName": "new_AccountName",
      "IsPrimaryName": true,
      "FormatName": { "Value": "Text" },
      "MaxLength": 100,
      "RequiredLevel": {
        "Value": "None",
        "CanBeChanged": true,
        "ManagedPropertyLogicalName": "canmodifyrequirementlevelsettings"
      },
      "DisplayName": {
        "@odata.type": "Microsoft.Dynamics.CRM.Label",
        "LocalizedLabels": [
          {
            "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel",
            "Label": "Account Name",
            "LanguageCode": 1033
          }
        ]
      },
      "Description": {
        "@odata.type": "Microsoft.Dynamics.CRM.Label",
        "LocalizedLabels": [
          {
            "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel",
            "Label": "Type the name of the bank account",
            "LanguageCode": 1033
          }
        ]
      }
    }
  ]
}

Response:

HTTP/1.1 204 No Content
OData-Version: 4.0
OData-EntityId: [Organization URI]/api/data/v9.2/EntityDefinitions(00aa00aa-bb11-cc22-dd33-44ee44ee44ee)

4.3 Elastic table

Identické jako standardní tabulka, jen přidáte:

"TableType": "Elastic"

4.4 Update tabulky

PUT na EntityDefinitions(<id>) s kompletním JSON (viz oficiální docs — výstup obsahuje desítky vlastností typu IsAuditEnabled, IsCustomizable, Privileges[] atd.). Doporučený postup:

  1. GET tabulku se všemi properties.
  2. Modifikujte jen to, co chcete změnit.
  3. Pošlete PUT s upraveným payloadem.
  4. Přidejte hlavičku MSCRM.MergeLabels: true, abyste si nepřepsali existující lokalizace v jiných jazycích.

5. Vytváření sloupců (Attributes)

5.1 Společný pattern

Endpoint:

POST /api/data/v9.2/EntityDefinitions(LogicalName='<entitylogicalname>')/Attributes

Každý sloupec musí mít: - @odata.type — fully-qualified název typu (např. Microsoft.Dynamics.CRM.StringAttributeMetadata) - AttributeType — enum hodnota (např. "String") - AttributeTypeName.Value — string typ (např. "StringType") — JE ROZDÍL mezi AttributeType a AttributeTypeName - SchemaName (s publisher prefixem) - DisplayName, Description jako Label s LocalizedLabels - RequiredLevel jako objekt s Value, CanBeChanged, ManagedPropertyLogicalName

5.2 Tabulka typů sloupců

Typ sloupce @odata.type AttributeType AttributeTypeName.Value Klíčové vlastnosti
String StringAttributeMetadata String StringType FormatName (Text, Email, Url, Phone, TextArea, …), MaxLength
Memo (multi-line text) MemoAttributeMetadata Memo MemoType Format (Text/TextArea/Email/Json/RichText), MaxLength, ImeMode
Integer (Whole Number) IntegerAttributeMetadata Integer IntegerType MinValue, MaxValue, Format (None/Duration/TimeZone/Language)
BigInt BigIntAttributeMetadata BigInt BigIntType
Decimal DecimalAttributeMetadata Decimal DecimalType MinValue, MaxValue, Precision
Money MoneyAttributeMetadata Money MoneyType PrecisionSource (0=fixed, 1=org default, 2=record's transaction currency)
DateTime DateTimeAttributeMetadata DateTime DateTimeType Format (DateOnly/DateAndTime), DateTimeBehavior
Boolean BooleanAttributeMetadata Boolean BooleanType OptionSet.TrueOption, OptionSet.FalseOption, DefaultValue
Picklist (Choice) — lokální PicklistAttributeMetadata Picklist PicklistType OptionSet.Options[], OptionSet.IsGlobal: false
Picklist — globální PicklistAttributeMetadata Picklist PicklistType GlobalOptionSet@odata.bind
MultiSelect Choice MultiSelectPicklistAttributeMetadata Virtual MultiSelectPicklistType OptionSet.Options[]
Lookup (běžný) LookupAttributeMetadata Lookup LookupType Vytváří se přes 1:N relationship, viz sekce 7
Customer Lookup ComplexLookupAttributeMetadata Lookup LookupType Speciální action CreateCustomerRelationships

5.3 String sloupec

POST /api/data/v9.2/EntityDefinitions(LogicalName='sample_bankaccount')/Attributes
MSCRM.SolutionUniqueName: examplesolution
Content-Type: application/json; charset=utf-8

{
  "@odata.type": "Microsoft.Dynamics.CRM.StringAttributeMetadata",
  "AttributeType": "String",
  "AttributeTypeName": { "Value": "StringType" },
  "SchemaName": "new_BankName",
  "FormatName": { "Value": "Text" },
  "MaxLength": 100,
  "RequiredLevel": {
    "Value": "None",
    "CanBeChanged": true,
    "ManagedPropertyLogicalName": "canmodifyrequirementlevelsettings"
  },
  "DisplayName": {
    "@odata.type": "Microsoft.Dynamics.CRM.Label",
    "LocalizedLabels": [
      { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Bank Name", "LanguageCode": 1033 }
    ]
  },
  "Description": {
    "@odata.type": "Microsoft.Dynamics.CRM.Label",
    "LocalizedLabels": [
      { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Type the name of the bank", "LanguageCode": 1033 }
    ]
  }
}

5.4 Money sloupec

{
  "@odata.type": "Microsoft.Dynamics.CRM.MoneyAttributeMetadata",
  "AttributeType": "Money",
  "AttributeTypeName": { "Value": "MoneyType" },
  "SchemaName": "new_Balance",
  "PrecisionSource": 2,
  "RequiredLevel": { "Value": "None", "CanBeChanged": true, "ManagedPropertyLogicalName": "canmodifyrequirementlevelsettings" },
  "DisplayName": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Balance", "LanguageCode": 1033 } ] },
  "Description": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Enter the balance amount", "LanguageCode": 1033 } ] }
}

PrecisionSource: 2 znamená, že precision se odvozuje z transakční měny záznamu.

5.5 DateTime sloupec

{
  "@odata.type": "Microsoft.Dynamics.CRM.DateTimeAttributeMetadata",
  "AttributeType": "DateTime",
  "AttributeTypeName": { "Value": "DateTimeType" },
  "SchemaName": "new_Checkeddate",
  "Format": "DateOnly",
  "RequiredLevel": { "Value": "None", "CanBeChanged": true, "ManagedPropertyLogicalName": "canmodifyrequirementlevelsettings" },
  "DisplayName": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Date", "LanguageCode": 1033 } ] }
}

5.6 Boolean sloupec

{
  "@odata.type": "Microsoft.Dynamics.CRM.BooleanAttributeMetadata",
  "AttributeType": "Boolean",
  "AttributeTypeName": { "Value": "BooleanType" },
  "SchemaName": "new_Boolean",
  "DefaultValue": false,
  "OptionSet": {
    "OptionSetType": "Boolean",
    "TrueOption": {
      "Value": 1,
      "Label": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "True", "LanguageCode": 1033 } ] }
    },
    "FalseOption": {
      "Value": 0,
      "Label": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "False", "LanguageCode": 1033 } ] }
    }
  },
  "RequiredLevel": { "Value": "None", "CanBeChanged": false, "ManagedPropertyLogicalName": "canmodifyrequirementlevelsettings" },
  "DisplayName": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Sample Boolean", "LanguageCode": 1033 } ] }
}

5.7 Picklist — lokální optionset

{
  "@odata.type": "Microsoft.Dynamics.CRM.PicklistAttributeMetadata",
  "AttributeType": "Picklist",
  "AttributeTypeName": { "Value": "PicklistType" },
  "SchemaName": "sample_Choice",
  "OptionSet": {
    "@odata.type": "Microsoft.Dynamics.CRM.OptionSetMetadata",
    "IsGlobal": false,
    "OptionSetType": "Picklist",
    "Options": [
      {
        "Value": 727000000,
        "Label": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Bravo", "LanguageCode": 1033 } ] }
      },
      {
        "Value": 727000001,
        "Label": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Delta", "LanguageCode": 1033 } ] }
      }
    ]
  },
  "RequiredLevel": { "Value": "None", "CanBeChanged": false, "ManagedPropertyLogicalName": "canmodifyrequirementlevelsettings" },
  "DisplayName": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Sample Choice", "LanguageCode": 1033 } ] }
}

Doporučení: pokud necháte Value jako null, systém doplní hodnotu s prefixem definovaným publisherem (customizationoptionvalueprefix). To je výhodné pro správu duplicit napříč prostředími.

5.8 Multi-select picklist

Téměř identický s Picklist, ale @odata.type je MultiSelectPicklistAttributeMetadata, AttributeType je Virtual a AttributeTypeName.Value je MultiSelectPicklistType.

5.9 Customer Lookup (speciální action)

Customer lookup není standardní lookup — má relace na account i contact současně. Vytváří se přes CreateCustomerRelationships Action:

POST /api/data/v9.2/CreateCustomerRelationships HTTP/1.1
MSCRM.SolutionUniqueName: examplesolution

{
  "OneToManyRelationships": [
    { "SchemaName": "new_bankaccount_customer_account", "ReferencedEntity": "account",  "ReferencingEntity": "new_bankaccount" },
    { "SchemaName": "new_bankaccount_customer_contact", "ReferencedEntity": "contact",  "ReferencingEntity": "new_bankaccount" }
  ],
  "Lookup": {
    "@odata.type": "Microsoft.Dynamics.CRM.ComplexLookupAttributeMetadata",
    "AttributeType": "Lookup",
    "AttributeTypeName": { "Value": "LookupType" },
    "SchemaName": "new_CustomerId",
    "DisplayName":  { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Customer", "LanguageCode": 1033 } ] },
    "Description":  { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Sample Customer Lookup Attribute", "LanguageCode": 1033 } ] }
  }
}

Response obsahuje RelationshipIds (pole se dvěma GUID) a AttributeId.

5.10 Update sloupce

Stejný princip jako u tabulky — vytáhněte plnou definici typu, modifikujte, pošlete PUT:

PUT /api/data/v9.2/EntityDefinitions(LogicalName='new_bankaccount')/Attributes(LogicalName='new_boolean') HTTP/1.1
MSCRM.SolutionUniqueName: examplesolution
MSCRM.MergeLabels: true
Content-Type: application/json; charset=utf-8

{ ...kompletní BooleanAttributeMetadata s upravenými hodnotami... }

⚠️ Pro úpravu options v Picklistu/Boolean se PUT nepoužívá — existují samostatné akce: InsertOptionValue, UpdateOptionValue, DeleteOptionValue, OrderOption, InsertStatusValue, UpdateStateValue.


6. Globální choices (GlobalOptionSetDefinitions)

6.1 Vytvoření globálního optionsetu

POST /api/data/v9.2/GlobalOptionSetDefinitions HTTP/1.1
MSCRM.SolutionUniqueName: examplesolution

{
  "@odata.type": "Microsoft.Dynamics.CRM.OptionSetMetadata",
  "Name": "sample_colors",
  "OptionSetType": "Picklist",
  "IsGlobal": true,
  "DisplayName": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Colors", "LanguageCode": 1033 } ] },
  "Description":  { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Color Choice", "LanguageCode": 1033 } ] },
  "Options": [
    { "Value": 727000000, "Label": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Red", "LanguageCode": 1033 } ] } },
    { "Value": 727000001, "Label": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Yellow", "LanguageCode": 1033 } ] } },
    { "Value": 727000002, "Label": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Green", "LanguageCode": 1033 } ] } }
  ]
}

6.2 Vytvoření Picklist sloupce navázaného na globální optionset

{
  "@odata.type": "Microsoft.Dynamics.CRM.PicklistAttributeMetadata",
  "AttributeType": "Picklist",
  "AttributeTypeName": { "Value": "PicklistType" },
  "SchemaName": "sample_Colors",
  "GlobalOptionSet@odata.bind": "/GlobalOptionSetDefinitions(Name='sample_colors')",
  "RequiredLevel": { "Value": "None", "CanBeChanged": false, "ManagedPropertyLogicalName": "canmodifyrequirementlevelsettings" },
  "DisplayName": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Sample Colors", "LanguageCode": 1033 } ] }
}

@odata.bind může používat alternativní klíč Name nebo MetadataId.

6.3 Operace nad options

Akce Účel URL
InsertOptionValue Přidat option do optionsetu POST /api/data/v9.2/InsertOptionValue
UpdateOptionValue Změnit label/popis option POST /api/data/v9.2/UpdateOptionValue
DeleteOptionValue Odstranit option POST /api/data/v9.2/DeleteOptionValue
OrderOption Změnit pořadí options POST /api/data/v9.2/OrderOption
InsertStatusValue Přidat status do statecode sloupce POST /api/data/v9.2/InsertStatusValue
UpdateStateValue Update statecode option POST /api/data/v9.2/UpdateStateValue

Všechny akce přijímají parametr SolutionUniqueName v body — díky tomu se změny propagují do uvedené solution.

Příklad DeleteOptionValue (rozlišení globální vs. lokální): - Globální: použijte parametr OptionSetName - Lokální (na sloupci): použijte parametry EntityLogicalName a AttributeLogicalName

6.4 Update samotného optionsetu

PUT /api/data/v9.2/GlobalOptionSetDefinitions(<id>) s OptionSetMetadataBase — ale pouze meta vlastnosti (DisplayName, Description). Options se mění výhradně přes akce výše.


7. Vztahy (RelationshipDefinitions)

7.1 Kontrola eligibility (před vytvořením)

Action / Function Co dělá
CanBeReferenced Může být primární (1) v 1:N relaci?
CanBeReferencing Může být referencing (N) v 1:N relaci?
CanManyToMany Může se účastnit N:N?
GetValidReferencedEntities Které entity může referencovat?
GetValidReferencingEntities Které entity ji mohou referencovat?
GetValidManyToMany Které entity podporují N:N?

Příklad:

GET /api/data/v9.2/GetValidReferencingEntities(ReferencedEntityName='sample_bankaccount')
POST /api/data/v9.2/CanManyToMany
{ "EntityName": "contact" }

7.2 Vytvoření 1:N relace (zároveň vytvoří lookup column)

POST /api/data/v9.2/RelationshipDefinitions HTTP/1.1
MSCRM.SolutionUniqueName: examplesolution
Content-Type: application/json; charset=utf-8

{
  "@odata.type": "Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata",
  "SchemaName": "new_contact_new_bankaccount",
  "ReferencedEntity": "contact",
  "ReferencingEntity": "new_bankaccount",
  "ReferencedAttribute": "contactid",
  "AssociatedMenuConfiguration": {
    "Behavior": "UseCollectionName",
    "Group": "Details",
    "Order": 10000,
    "Label": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Bank Accounts", "LanguageCode": 1033 } ] }
  },
  "CascadeConfiguration": {
    "Assign": "Cascade", "Delete": "Cascade", "Merge": "Cascade",
    "Reparent": "Cascade", "Share": "Cascade", "Unshare": "Cascade"
  },
  "Lookup": {
    "@odata.type": "Microsoft.Dynamics.CRM.LookupAttributeMetadata",
    "AttributeType": "Lookup",
    "AttributeTypeName": { "Value": "LookupType" },
    "SchemaName": "new_AccountOwner",
    "RequiredLevel": { "Value": "ApplicationRequired", "CanBeChanged": true, "ManagedPropertyLogicalName": "canmodifyrequirementlevelsettings" },
    "DisplayName": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Account Owner", "LanguageCode": 1033 } ] },
    "Description": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "The owner of the account", "LanguageCode": 1033 } ] }
  }
}

Toto je deep insert — lookup column je definovaný uvnitř relace a oba vznikají v jedné operaci.

7.3 Vytvoření N:N relace

POST /api/data/v9.2/RelationshipDefinitions HTTP/1.1
MSCRM.SolutionUniqueName: examplesolution

{
  "@odata.type": "Microsoft.Dynamics.CRM.ManyToManyRelationshipMetadata",
  "SchemaName": "new_accounts_campaigns",
  "Entity1LogicalName": "account",
  "Entity2LogicalName": "campaign",
  "IntersectEntityName": "new_accounts_campaigns",
  "Entity1AssociatedMenuConfiguration": { "Behavior": "UseLabel", "Group": "Details", "Order": 10000, "Label": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Account", "LanguageCode": 1033 } ] } },
  "Entity2AssociatedMenuConfiguration": { "Behavior": "UseLabel", "Group": "Details", "Order": 10000, "Label": { "@odata.type": "Microsoft.Dynamics.CRM.Label", "LocalizedLabels": [ { "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel", "Label": "Campaign", "LanguageCode": 1033 } ] } }
}

7.4 Retrieve relace s castem

GET /api/data/v9.2/RelationshipDefinitions(<id>)/Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata
GET /api/data/v9.2/RelationshipDefinitions(<id>)/Microsoft.Dynamics.CRM.ManyToManyRelationshipMetadata
GET /api/data/v9.2/RelationshipDefinitions(SchemaName='Account_Tasks')/Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata

Bez castu dostanete jen společné properties z RelationshipMetadataBase.

7.5 Update / Delete relace


8. Propagace do solution

8.1 Doporučená cesta — MSCRM.SolutionUniqueName hlavička

Pokaždé, když děláte POST (create) nebo PUT (update) na schema endpoint a chcete prvek umístit do konkrétní solution, přidejte:

MSCRM.SolutionUniqueName: yoursolutionuniquename

Funguje pro: - EntityDefinitions (POST/PUT/DELETE) - EntityDefinitions(...)/Attributes (POST/PUT/DELETE) - RelationshipDefinitions (POST/PUT/DELETE) - GlobalOptionSetDefinitions (POST/PUT/DELETE) - Akce pro options: InsertOptionValue, UpdateOptionValue, DeleteOptionValue, OrderOption, InsertStatusValue (předává se jako parametr SolutionUniqueName v body, ne jako hlavička) - CreateCustomerRelationships

8.2 Alternativa — AddSolutionComponent action

Pokud už komponenta existuje (např. system entity account) a potřebujete ji jen přidat do solution, použijte action AddSolutionComponent:

POST /api/data/v9.2/AddSolutionComponent HTTP/1.1
Content-Type: application/json; charset=utf-8

{
  "ComponentId": "70816501-edb9-4740-a16c-6a5efbc05d84",
  "ComponentType": 1,
  "SolutionUniqueName": "yoursolutionuniquename",
  "AddRequiredComponents": false,
  "DoNotIncludeSubcomponents": false
}

Klíčové ComponentType hodnoty (z globální choice componenttype):

Value Component
1 Entity (tabulka)
2 Attribute (sloupec)
9 OptionSet
10 EntityRelationship
60 SystemForm
61 WebResource
300 Canvas App
380 Environment Variable Definition
381 Environment Variable Value

⚠️ AddSolutionComponent použijte jen tehdy, když znáte správný ComponentType. U novějších komponent (které ještě nejsou v componenttype choice) preferujte MSCRM.SolutionUniqueName hlavičku.

8.3 Vytvoření samotné solution přes Web API

Solution je standardní business entita. Vytvoříte přes POST /api/data/v9.2/solutions se vztahem na publishera:

POST /api/data/v9.2/solutions HTTP/1.1
Content-Type: application/json; charset=utf-8

{
  "uniquename": "examplesolution",
  "friendlyname": "Example Solution",
  "version": "1.0.0.0",
  "publisherid@odata.bind": "/publishers(<publisherId GUID>)"
}

Publisher musí existovat předem — POST /api/data/v9.2/publishers s uniquename, friendlyname a customizationprefix.

8.4 Co se stane s default solution

Když přidáte komponentu pomocí MSCRM.SolutionUniqueName, dojde k tomu, že: 1. Komponenta vznikne v default (active) solution — to platí vždy. 2. Zároveň je přidána i do vaší explicitní unmanaged solution.

Pokud hlavičku vynecháte, komponenta skončí jen v default solution a musíte ji následně přidat pomocí AddSolutionComponent.


9. Publikování změn

Bez publikování se některé změny schématu neprojeví v UI ani se neexportují se solution. Publikování je nutné po každém update (vytváření nových komponent ho vyžaduje méně často, protože nové komponenty se publikují automaticky).

9.1 PublishAllXml — publikuje vše

POST /api/data/v9.2/PublishAllXml HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
Accept: application/json

Bez body. Vrací 204 No Content. Pozor — v produkci to může na chvíli zatížit prostředí.

9.2 PublishXml — selektivní

POST /api/data/v9.2/PublishXml HTTP/1.1
Content-Type: application/json; charset=utf-8

{
  "ParameterXml": "<importexportxml><entities><entity>new_bankaccount</entity><entity>account</entity></entities></importexportxml>"
}

ParameterXml musí splňovat Publish Request Schema. Dovolené sekce uvnitř <importexportxml>: - <entities> — seznam tabulek (<entity>logicalname</entity>) - <ribbons><ribbon></ribbon> (publikuje application ribbon) - <entitymaps/>, <entityrelationships>, <optionsets>, <dashboards>, <webresources>, <sitemaps>

Příklad pro více typů komponent:

<importexportxml>
  <entities>
    <entity>new_bankaccount</entity>
  </entities>
  <optionsets>
    <optionset>sample_colors</optionset>
  </optionsets>
  <webresources>
    <webresource>{a7d261bc-3580-e611-80d7-00155d2a68de}</webresource>
  </webresources>
</importexportxml>

9.3 Kdy publikovat

Akce Auto-publish Nutné publish
Vytvoření nové tabulky/sloupce Ano Ne
Smazání komponenty Ano Ne
Update tabulky/sloupce Ne Ano
Update labelů, optionsetů Ne Ano
Změna IsAuditEnabled, RequiredLevel apod. Ne Ano
Před exportem solution Ano vždy

10. Kompletní příklad workflow

Scénář: Skript, který v solution MyExtensions zajistí existenci tabulky new_bankaccount se sloupcem new_iban (string, max 34) a sloupcem new_balance (money).

# 1) Existuje tabulka?
GET /api/data/v9.2/EntityDefinitions(LogicalName='new_bankaccount')?$select=MetadataId,LogicalName

  └─ 404 → vytvořit:
     POST /api/data/v9.2/EntityDefinitions
     Headers:
       MSCRM.SolutionUniqueName: MyExtensions
     Body: viz sekce 4.2 (BankAccount s primárním atributem new_AccountName)

  └─ 200 → pokračovat, máme MetadataId

# 2) Existuje sloupec new_iban?
GET /api/data/v9.2/EntityDefinitions(LogicalName='new_bankaccount')
    /Attributes(LogicalName='new_iban')?$select=MetadataId

  └─ 404 → vytvořit:
     POST /api/data/v9.2/EntityDefinitions(LogicalName='new_bankaccount')/Attributes
     Headers:
       MSCRM.SolutionUniqueName: MyExtensions
     Body:
     {
       "@odata.type": "Microsoft.Dynamics.CRM.StringAttributeMetadata",
       "AttributeType": "String",
       "AttributeTypeName": { "Value": "StringType" },
       "SchemaName": "new_IBAN",
       "FormatName": { "Value": "Text" },
       "MaxLength": 34,
       "RequiredLevel": { "Value": "Recommended", "CanBeChanged": true, "ManagedPropertyLogicalName": "canmodifyrequirementlevelsettings" },
       "DisplayName": { "@odata.type":"Microsoft.Dynamics.CRM.Label","LocalizedLabels":[{"@odata.type":"Microsoft.Dynamics.CRM.LocalizedLabel","Label":"IBAN","LanguageCode":1033}] },
       "Description":  { "@odata.type":"Microsoft.Dynamics.CRM.Label","LocalizedLabels":[{"@odata.type":"Microsoft.Dynamics.CRM.LocalizedLabel","Label":"Bank account international number","LanguageCode":1033}] }
     }

# 3) Existuje sloupec new_balance?
GET /api/data/v9.2/EntityDefinitions(LogicalName='new_bankaccount')
    /Attributes(LogicalName='new_balance')?$select=MetadataId

  └─ 404 → vytvořit:
     POST /api/data/v9.2/EntityDefinitions(LogicalName='new_bankaccount')/Attributes
     Headers:
       MSCRM.SolutionUniqueName: MyExtensions
     Body:
     {
       "@odata.type": "Microsoft.Dynamics.CRM.MoneyAttributeMetadata",
       "AttributeType": "Money",
       "AttributeTypeName": { "Value": "MoneyType" },
       "SchemaName": "new_Balance",
       "PrecisionSource": 2,
       "RequiredLevel": { "Value": "None", "CanBeChanged": true, "ManagedPropertyLogicalName": "canmodifyrequirementlevelsettings" },
       "DisplayName": { "@odata.type":"Microsoft.Dynamics.CRM.Label","LocalizedLabels":[{"@odata.type":"Microsoft.Dynamics.CRM.LocalizedLabel","Label":"Balance","LanguageCode":1033}] }
     }

# 4) Publikovat změny
POST /api/data/v9.2/PublishXml
{
  "ParameterXml": "<importexportxml><entities><entity>new_bankaccount</entity></entities></importexportxml>"
}

Pseudokód v C# (HttpClient styl)

async Task EnsureAttributeAsync(HttpClient http, string solution, string entityLogicalName, string attrLogicalName, object attributeDefinition)
{
    var getResp = await http.GetAsync(
        $"api/data/v9.2/EntityDefinitions(LogicalName='{entityLogicalName}')" +
        $"/Attributes(LogicalName='{attrLogicalName}')?$select=MetadataId");

    if (getResp.StatusCode == HttpStatusCode.OK)
        return; // attribute exists

    if (getResp.StatusCode != HttpStatusCode.NotFound)
        getResp.EnsureSuccessStatusCode();

    var req = new HttpRequestMessage(HttpMethod.Post,
        $"api/data/v9.2/EntityDefinitions(LogicalName='{entityLogicalName}')/Attributes")
    {
        Content = JsonContent.Create(attributeDefinition)
    };
    req.Headers.Add("MSCRM.SolutionUniqueName", solution);
    req.Headers.Add("OData-MaxVersion", "4.0");
    req.Headers.Add("OData-Version", "4.0");

    var postResp = await http.SendAsync(req);
    postResp.EnsureSuccessStatusCode();
}

11. Best practices a úskalí

  1. Vždy používejte $select při čtení metadat — EntityMetadata má desítky vlastností.
  2. Cast expressions jsou case-sensitive a používají fully-qualified namespace Microsoft.Dynamics.CRM.<TypeName>.
  3. Update = PUT s celou definicí, ne PATCH. Vždy nejprve GET, modify, PUT.
  4. Při update labelů používejte MSCRM.MergeLabels: true, jinak smažete lokalizace v jiných jazycích.
  5. Hlavička MSCRM.SolutionUniqueName má přednost před AddSolutionComponent — preferujte ji.
  6. Vždy publikujte po update (vytvoření obvykle ne, update vždy).
  7. Před exportem solution publikujte všechnoPublishAllXml.
  8. U Options v Picklistu nechte Value: null, ať systém přiřadí prefix publishera — zabráníte kolizím při merge solution.
  9. Pro retrieve metadat preferujte Consistency: Strong hlavičku.
  10. Atributy nelze dotazovat samostatně — vždy v kontextu tabulky.
  11. Žádné stránkování u metadat — používejte filter + select.
  12. Pro velký objem nebo cache schématu používejte RetrieveMetadataChanges s ClientVersionStamp.
  13. Eligibility check před vytvořením relace — ne všechny entity podporují všechny typy relací.
  14. AttributeType vs. AttributeTypeName — obojí musíte poslat, jinak request selže s nečitelnou chybou.
  15. DisplayName / Description / Label vždy musí mít @odata.type "Microsoft.Dynamics.CRM.Label" a uvnitř LocalizedLabel s LanguageCode.

12. Reference

Oficiální dokumentace: - Use the Web API with table definitions — přehled - Query Table Definitions Using the Web API — čtení metadat - Retrieve table definitions by name or MetadataId — retrieve podle klíče - Create and update table definitions using the Web API — tabulky - Create and update column definitions using the Web API — sloupce - Create and update choices (option sets) using the Web API — globální choices - Create and update table relationships using the Web API — vztahy - Use optional parameters — Associate a solution component with a solution - Publish customizations - Web API table schema operations sample — end-to-end sample - Web API table schema operations sample (PowerShell) - Web API service documents (CSDL $metadata)

Reference entity types (kompletní property listy): - EntityMetadata EntityType - AttributeMetadata EntityType (a všechny derived: StringAttributeMetadata, IntegerAttributeMetadata, DecimalAttributeMetadata, MoneyAttributeMetadata, MemoAttributeMetadata, DateTimeAttributeMetadata, BooleanAttributeMetadata, PicklistAttributeMetadata, MultiSelectPicklistAttributeMetadata, LookupAttributeMetadata, BigIntAttributeMetadata, ImageAttributeMetadata, FileAttributeMetadata, atd.) - OneToManyRelationshipMetadata / ManyToManyRelationshipMetadata - OptionSetMetadata / BooleanOptionSetMetadata - PublishXml Action / PublishAllXml Action - AddSolutionComponent Action - CreateCustomerRelationships Action - RetrieveMetadataChanges Function