Langage TMDL (Tabular Model Definition Language)

S’applique à : SQL Server 2016 et versions ultérieures Analysis Services Azure Analysis Services Fabric/Power BI Premium

Important

Le langage TMDL (Tabular Model Definition Language) est actuellement en préversion. Pendant la période de préversion, les fonctionnalités et la documentation sont susceptibles de changer.

Le langage TMDL (Tabular Model Definition Language) est une syntaxe de définition de modèle objet pour les modèles de données tabulaires au niveau de compatibilité 1200 ou supérieur.

Les éléments clés de TMDL sont les suivants :

  • Compatibilité totale avec l’ensemble du modèle d’objet tabulaire (TOM). Chaque objet TMDL expose les mêmes propriétés que TOM.
  • Basé sur du texte et optimisé pour l’interaction humaine et la lisibilité. TMDL utilise une syntaxe grammaticale similaire à YAML. Chaque objet TMDL est représenté dans du texte avec des délimiteurs minimaux et utilise la mise en retrait pour délimiter les relations parent-enfant.
  • Meilleure expérience d’édition, en particulier sur les propriétés avec des expressions incorporées de différents types de contenu, comme DAX (Data Analysis Expression) et M.
  • Mieux pour la collaboration en raison de sa représentation de dossier où chaque objet de modèle a une représentation de fichier individuelle, ce qui le rend plus convivial pour le contrôle de code source.

Un aspect important de TMDL est l’utilisation de la mise en retrait d’espace blanc pour désigner une structure d’objet TOM. L’exemple suivant montre à quel point il est facile de représenter un modèle tabulaire lors de l’utilisation de TMDL :

database Sales
	compatibilityLevel: 1567	

model Model    
    culture: en-US    

table Sales
    
    partition 'Sales-Partition' = m
        mode: import
        source = 
            let
                Source = Sql.Database(Server, Database)
                …
    
    measure 'Sales Amount' = SUMX('Sales', 'Sales'[Quantity] * 'Sales'[Net Price])
        formatString: $ #,##0
   
    column 'Product Key'
        dataType: int64
        isHidden
        sourceColumn: ProductKey
        summarizeBy: None
 
    column Quantity
        dataType: int64
        isHidden
        sourceColumn: Quantity
        summarizeBy: None

    column 'Net Price'
        dataType: int64
        isHidden
        sourceColumn: "Net Price"
        summarizeBy: none

table Product
    
    partition 'Product-Partition' = m
        mode: import
        source = 
            let
                Source = Sql.Database(Server, Database),
                …

    column 'Product Key'
        dataType: int64
        isKey
        sourceColumn: ProductKey
        summarizeBy: none

relationship cdb6e6a9-c9d1-42b9-b9e0-484a1bc7e123
    fromColumn: Sales.'Product Key'
    toColumn: Product.'Product Key'

role Role_Store1
    modelPermission: read

    tablePermission Store = 'Store'[Store Code] IN {1,10,20,30}

expression Server = "localhost" meta [IsParameterQuery=true, Type="Text", IsParameterQueryRequired=true]

expression Database = "Contoso" meta [IsParameterQuery=true, Type="Text", IsParameterQueryRequired=true]

Structure des dossiers TMDL

Contrairement à TMSL, TMDL utilise une structure de dossiers. La structure de dossiers par défaut n’a qu’un seul niveau de sous-dossiers, tous avec des fichiers .tmdl à l’intérieur :

  • cultures
  • perspectives
  • roles
  • dans des tables

Et les fichiers racines pour :

  • database
  • model
  • relationships
  • expressions
  • datasources

Voici un exemple de dossier TMDL :

Dossier avec une représentation TMDL d’un modèle

Les définitions sont les suivantes :

  • Un fichier pour la définition de base de données.
  • Un fichier pour la définition de modèle.
  • Un fichier pour toutes les sources de données dans le modèle.
  • Un fichier pour toutes les expressions du modèle.
  • Un fichier pour toutes les relations dans le modèle.
  • Un fichier pour chaque schéma linguistique de culture.
  • Un fichier pour chaque perspective.
  • Un fichier pour chaque rôle.
  • Un fichier pour chaque table.
  • Toutes les propriétés de métadonnées internes des tables (Column, Hierarchies, Partitions,...) se trouvent dans le fichier TMDL de la table parente.

TMDL API

À l’instar du langage TMSL (Tabular Model Scripting Language), il existe une classe pour gérer la sérialisation TMDL. Pour TMDL, la classe est TmdlSerializer, sous l’espace de noms Microsoft.AnalysisServices.Tabular .

La classe TmdlSerializer expose des méthodes pour sérialiser et désérialiser des documents TMDL :

Sérialisation des dossiers

public static void SerializeDatabaseToFolder (Database database, string path)

  • Reçoit un objet de base de données TOM et le chemin de sortie TMDL.
  • Sérialise la base de données TOM dans une représentation de dossier TMDL.

En savoir plus sur la sérialisation dans un dossier.

public static Database DeserializeDatabaseFromFolder (string path)

  • Reçoit un chemin d’accès complet à un dossier TMDL.
  • Retourne la représentation d’objet de base de données TOM du dossier TMDL.

En savoir plus sur la désérialisation à partir de dossiers.

Sérialisation de chaînes

public static string SerializeObject (MetadataObject object, bool qualifyObject = true)

  • Reçoit un objet TOM et retourne sa représentation textuelle TMDL.

En savoir plus sur la sérialisation d’un objet en chaîne.

Sérialisation de flux

Vous pouvez sérialiser/désérialiser TMDL vers/depuis des flux, ce qui vous permet de convertir un objet TOM en flux d’octets pour le stockage, la transmission et l’interopérabilité entre les plateformes. L’API Stream vous permet également de contrôler quels documents TMDL sont chargés et quels documents TMDL sont générés.

La sérialisation du flux TMDL est gérée par la classe MetadataSerializationContext .

En savoir plus sur la sérialisation vers/depuis TMDL à l’aide de flux.

Langage TMDL

Déclaration d’objet

À l’exception de l’objet Server, TMDL expose l’arborescence d’objets TOM Database entière dans l’espace de noms Microsoft.AnalysisServices.Tabular.

Un objet TMDL est déclaré en spécifiant le type d’objet TOM suivi de son nom. Dans l’exemple de code suivant, chaque type d’objet : model, tableest column suivi d’un nom d’objet.

model Model    
    culture: en-US    

table Sales
    
    measure Sales = SUM(…)
        formatString: $ #,##0

    column 'Customer Key'
        datatype: int64
        sourceColumn: CustomerKey

Les objets comme partition ou measure ont des propriétés par défaut qui peuvent être affectées après le délimiteur égal à (=) dans la même ligne de la déclaration d’objet ou dans la ligne suivante pour une expression multiligne :

table Sales

    partition Sales-Part1 = m
        mode: import
        ...        
    
    measure Sales = SUM(…)
        formatString: $ #,##0

    measure 'Sales (ly)' = 
            var ly = ...
            return ly
        formatString: $ #,##0

Le nom de l’objet TMDL doit être placé entre guillemets simples (') s’il comprend l’un des caractères suivants :

  • Point (.)
  • Est égal à (=)
  • Deux-points ( :)
  • Citation simple (')
  • Espace blanc ( )

Si un nom d’objet contient des guillemets simples ('), utilisez deux guillemets simples pour le placer dans une séquence d’échappement.

Propriétés des objets

Les propriétés de l’objet sont spécifiées après la déclaration d’objet ou l’expression de propriété par défaut de l’objet. Les valeurs de propriété d’objet sont spécifiées en suivant le délimiteur deux-points ( :). Par exemple :

table Sales
    lineageTag: e9374b9a-faee-4f9e-b2e7-d9aafb9d6a91    

    column Quantity
        dataType: int64
        isHidden
        isAvailableInMdx: false
        sourceColumn: Quantity

    measure 'Sales Amount' = 
            var result = SUMX(...)
            return result
  formatString: $ #,##0
  displayFolder: " My ""Amazing"" Measures"

Les règles suivantes s’appliquent aux valeurs de propriété :

  • La valeur doit se trouver dans la même ligne qui suit les deux-points et ne peut pas avoir plusieurs lignes.

  • Valeurs des propriétés text

    • Les guillemets doubles de début et de fin sont facultatifs et automatiquement supprimés pendant la sérialisation.
    • Doit être placé entre guillemets doubles (« ) si le texte contient un espace blanc de fin ou de début.
    • Lorsqu’elle est placée entre guillemets doubles, si la valeur contient des guillemets doubles, utilisez deux guillemets doubles pour les placer dans une séquence d’échappement (voir displayFolder la propriété dans l’exemple de code ci-dessus).
  • Les propriétés booléennes peuvent être définies à l’aide de la syntaxe de paire clé/valeur standard, comme avec la 'isAvailableInMdx' propriété dans l’exemple précédent. Ils peuvent également être définis à l’aide d’une syntaxe de raccourci où seul le nom de propriété est déclaré et true implicite. Consultez, par exemple, la propriété « isHidden » dans l’exemple précédent.

Références d’objets nommés

Certaines propriétés d’objet contiennent des références à d’autres objets de modèle, par exemple :

  • Référence de colonne dans les niveaux hiérarchiques.
  • référence sortByColumn dans chaque colonne de table.
  • Référence de table/colonne/mesure dans les perspectives.

Dans TMDL, les références sont effectuées à l’aide du nom de l’objet et suivent les mêmes exigences d’échappement et de guillemet unique (') de déclaration d’objet. Dans l’exemple de code suivant, vous voyez des propriétés d’objet qui contiennent une référence à un autre objet : column.sortByColumn, level.columnet perspectiveMeasure.measureperspectiveTable.table.


table Product

    column Category
        sortByColumn: 'Category Order'    

 hierarchy 'Product Hierarchy'

  level Category   
   column: Category  
 

perspective Product

 perspectiveTable Product

        perspectiveMeasure '# Products'

Si nécessaire pour référencer un nom complet, TMDL utilise la notation par points pour référencer un objet, par exemple : 'Table 1'.'Column 1'

Objets enfants

L’arborescence d’objets TOM contient des objets enfants à de nombreux endroits et à différents niveaux. Par exemple :

  • Un objet de modèle contient des objets de table, de rôle et d’expression.
  • Un objet table contient des objets de colonne, de mesure et de hiérarchie.

TMDL ne déclare pas explicitement les collections enfants. Au lieu de cela, tous les éléments enfants applicables dans l’étendue de leur parent respectif composent implicitement les éléments de la collection correspondante. Par exemple, tous les éléments de colonne dans l’étendue d’une table particulière deviennent des éléments de la collection columns de cette table dans TOM, comme illustré ici :

table Sales

    measure 'Sales Amount' = SUMX('Sales', [Quantity] * [Net Price])

    measure 'Total Quantity' = SUM('Sales'[Quantity])

    measure 'Sales Amount YTD' = TOTALYTD([Sales Amount], 'Calendar'[Date])    

Les objets enfants n’ont pas besoin d’être contigus. Par exemple, vous pouvez déclarer des colonnes et des mesures dans n’importe quel ordre et entremêlées.

Propriétés par défaut

Certains types d’objets ont une propriété par défaut qui est la plupart du temps traitée comme des expressions. La propriété par défaut est spécifique au type d’objet. Le cas échéant, la valeur ou l’expression de propriété est spécifiée à la suite du délimiteur égal à (=) après la déclaration de section.

Syntaxe prise en charge :

  • La valeur est spécifiée sur la même ligne que l’en-tête de section.
  • La valeur est spécifiée en tant qu’expression multiligne après l’en-tête de section.

Dans l’exemple de code suivant, la mesure Sales Amount et la partition Sales-Partition1 sont une seule ligne et la mesure Quantity est multiligne :

table Sales

    measure 'Sales Amount' = SUM(...)
        formatString: $ #,##0

    measure Quantity = 
            var result = SUMX (...)
            return result
        formatString: #,##0

    partition Sales-Partition1 = m
  mode: import
  source =
   let
       ...
   in
       finalStep

Expressions

Il existe des propriétés d’objet qui, tout en étant une propriété de texte dans TOM, obtiennent une analyse spéciale dans TMDL. L’intégralité du texte est lue textuellement, car elle peut inclure des caractères spéciaux tels que des guillemets ou des crochets dans les expressions M ou DAX. Les expressions peuvent être multilignes ou monolignes. S’ils sont multilignes, ils doivent se trouver dans la ligne immédiatement après la déclaration de propriété ou d’objet.

Une valeur d’expression dans TMDL est spécifiée à la suite d’un délimiteur égal à (=), comme dans l’exemple suivant :

table Table1

    partition 'partition 1' = m
        mode: import
        source =
            let
            ...
            in
                finalStep
    
    measure Measure1 = SUM(...)

    measure Measure2 =
            var result = SUMX ( 
                ...
            )
            return result
        formatString: $ #,##0

Les règles spéciales suivantes s’appliquent aux expressions :

  • Les expressions multilignes doivent être mises en retrait d’un niveau plus profond dans les propriétés de l’objet parent, et l’expression entière doit se trouver dans ce niveau de retrait.
  • Tous les espaces blancs de retrait externe sont supprimés au-delà du niveau de retrait de l’objet parent.
  • Les espaces blancs verticaux (lignes vides sans espaces blancs) sont autorisés et sont considérés comme faisant partie de l’expression.
  • Les lignes vides et les espaces blancs de fin sont supprimés.
  • Pour appliquer une mise en retrait différente ou pour conserver les lignes vides ou les espaces blancs de fin, utilisez les trois accents (```) englobants.
  • Par défaut, le sérialiseur TMDL contient des accents inverses si la valeur de l’expression contient quelque chose qui pourrait entraîner une modification lors d’un aller-retour (par exemple, des espaces blancs de fin, des lignes vides avec des espaces blancs).

Les expressions entourées de trois accents (```) sont lues textuellement, notamment la mise en retrait, les lignes vides et les espaces blancs. Le délimiteur doit être appliqué immédiatement après le signe égal (=) et la ligne qui suit l’expression et ne peut avoir rien après, comme dans l’exemple suivant :

table Table1

    partition partition1 = m
        mode: import
        source = ```
            let
            ...
            in
                finalStep

            ```

    measure Measure1 = ```
                var myVar = Today()
                …
                return result
            ```

L’utilisation du délimiteur à trois backticks (```) est facultative et nécessaire uniquement dans des situations uniques. Dans la plupart des cas, l’utilisation d’une mise en retrait et d’une déclaration d’objet correctes garantit une analyse correcte de l’expression que vous ajoutez à la propriété.

Lorsque l’expression est placée dans des backticks, les règles suivantes s’appliquent :

  • Tout ce qui se trouve entre trois backticks (```) est considéré comme faisant partie de l’expression multibloc et les règles de retrait TMDL ne sont pas appliquées. Le délimiteur de fin détermine la mise en retrait dans l’expression.
  • La mise en retrait relative dans l’expression est conservée. Le délimiteur de fin (```) détermine la limite de gauche de l’expression (voir « Measure1 » dans l’exemple précédent).

Les propriétés suivantes sont traitées comme des expressions :

Type d'objet Propriété Langage d’expression
Mesure Expression DAX
MPartitionSource Expression M
CalculatedPartitionSource Expression DAX
QueryPartitionSource Requête NativeQuery
CalculationItem Expression DAX
BasicRefreshPolicy SourceExpression, PollingExpression M
KPI StatusExpression, TargetExpression, TrendExpression DAX
LinguisticMetadata Contenu XML ou Json
JsonExtendedProperty Valeur Json
FormatStringDefintion Expression DAX
DataCoverageDefinition Expression DAX
CalculationGroupExpression Expression DAX
NamedExpression Expression DAX
DetailRowsDefinition Expression DAX
TablePermission FilterExpression DAX
CalculatedColumn Expression DAX

Propriétés par défaut par type d’objet

Le tableau suivant présente la propriété par défaut et le langage d’expression par type d’objet :

Type d’objet Propriété par défaut Langage d’expression
Mesure Expression DAX
CalculatedColumn Expression DAX
CalculationItem Expression DAX
FormatStringDefinition Expression DAX
DetailRowsDefinition Expression DAX
CalculationExpression Expression DAX
DataCoverageDefinition Expression DAX
TablePermission FilterExpression DAX
ColumnPermission MetadataPermission MetadataPermission, énumération
NamedExpression Expression M
MPartitionSource Expression M
CalculatedPartitionSource Expression DAX
JsonExtendedProperty Valeur Json
Annotation Valeur Texte
StringExtendedProperty Valeur Texte
DataSource Type DataSourceType, énumération
Partition SourceType PartitionSourceType, énumération
ChangedProperty Propriété Texte de la propriété
ExternalModelRoleMember MemberType Énumération RoleMemberType
Toute propriété JSON personnalisée (par exemple, DataAccessOptions) Document JSON Json
LinguisticMetadata Contenu Json

Descriptions

TMDL fournit une prise en charge de première classe pour les descriptions. À des fins de documentation de modèle, la meilleure pratique consiste à fournir des descriptions pour chaque objet TOM. TMDL traite les descriptions comme une propriété spéciale avec une prise en charge syntaxique explicite. À la suite des exemples de nombreux autres langages, les descriptions sont spécifiées par-dessus chaque déclaration d’objet à l’aide de la syntaxe à barres obliques triples (///).

Aucun espace blanc n’est autorisé entre la fin du bloc de description et le jeton de type d’objet.

Les descriptions peuvent être réparties sur plusieurs lignes. Le sérialiseur TMDL divise les descriptions d’objets en plusieurs lignes pour conserver les lignes de document émises sous la longueur maximale. La longueur maximale par défaut est de 80 caractères.

/// Table Description
table Sales

    /// This is the Measure Description
    /// One more line
    measure 'Sales Amount'' = SUM(...)
        formatString: #,##0

Déclaration partielle

TMDL ne force pas la déclaration d’objet dans le même document. Toutefois, il est similaire aux classes partielles C# où il est possible de fractionner la définition d’objet entre plusieurs fichiers. Par exemple, vous pouvez déclarer une définition de table dans un fichier [table].tmdl, puis avoir toutes les mesures de toutes les tables définies dans un seul fichier [measures].tmdl, comme illustré ici :

table Sales

    measure 'Sales Amount' = SUM(…)
        formatString: $ #,##0

table Product

    measure CountOfProduct = COUNTROWS(…)

Pour éviter une erreur d’analyse, la même propriété ne peut pas être déclarée deux fois. Par exemple, la déclaration de deux mesures portant le même nom pour la même table dans deux documents TMDL différents génère une erreur.

Références d'objets

Vous pouvez référencer un autre objet TMDL à l’aide de la référence mot clé suivie du type et du nom de l’objet.

Par exemple, si vous sérialisez un objet Column à l’aide de l’API de sérialisation de chaîne, le résultat sera :

ref table Table1
	column Column1
		datatype: int64
		sourceColumn: Column1

Classement déterministe des collections

La référence mot clé est également utilisée pour définir et conserver l’ordre de collecte sur les allers-retours TOM <> TMDL. Il est particulièrement important d’éviter les diff de contrôle de code source sur les objets TMDL qui sont sérialisés dans des fichiers individuels : tables, rôles, cultures et perspectives. Le mot clé ref est utilisé sur le fichier TMDL de l’objet parent pour déclarer le classement d’élément à partir de TOM :


model Model

ref table Calendar
ref table Sales
ref table Product
ref table Customer
ref table About

ref culture en-US
ref culture pt-PT

ref role 'Stores Cluster 1'
ref role 'Stores Cluster 2'

Les règles suivantes sont appliquées :

  • Pendant la désérialisation TMDL :
    • Les objets référencés dans TMDL, mais avec le fichier TMDL manquant, sont ignorés.
    • Les objets non référencés, mais avec un fichier TMDL existant, sont ajoutés à la fin de la collection.
  • Pendant la sérialisation TMDL :
    • Tous les objets de collection dans TOM sont référencés à l’aide de la référence mot clé.
    • Les collections avec un seul élément n’émettent pas de référence.
    • Les lignes vides ne sont pas émises entre les ref si le même type d’objet.

Délimiteurs de valeur de propriété

Il n’existe que deux délimiteurs/symboles pour affecter une valeur de propriété :

Indentation

TMDL utilise des règles de retrait d’espace blanc strictes pour délimiter la structure de la hiérarchie TOM. Un document TMDL utilise une règle de retrait par onglet unique par défaut.

Chaque objet peut avoir trois niveaux de retrait :

  • Niveau 1 - Déclaration d’objet
    • Niveau 2 - Propriétés de l’objet
      • Niveau 3 - Expressions multilignes de propriété d’objet

Dans un document TMDL, la mise en retrait est appliquée dans les cas suivants :

  • Entre un en-tête de section d’objet et les propriétés de l’objet (table -> propriétés).

    table Sales
        isHidden
        lineageTag: 9a48bea0-e5fb-40fa-9e81-f61288e31a02
    
  • Entre un objet et ses objets enfants (table -> mesures).

    table Sales
    
        measure 'Sales Amount' = SUMX(...)
    
        measure 'Total Quantity' = SUM(...)
    
  • Entre un objet et ses expressions multilignes (table -> mesure -> expression).

    table Sales
    
        measure 'Sales Amount' = 
                var result = SUMX(...)
                return result
            formatString: $ #,##0
    
  • Les expressions multilignes doivent être mises en retrait d’un niveau plus profond que les propriétés de l’objet et l’expression entière doit se trouver dans ce niveau de retrait (voir expressions).

La base de données et les objets enfants directs de Model n’ont pas besoin d’être mis en retrait, car ils sont implicitement supposés imbriqués sous le modèle racine ou la base de données :

  • model
  • dans des tables
  • expressions partagées
  • roles
  • cultures
  • perspectives
  • relationships
  • sources de données
  • groupes de requête
  • annotations au niveau du modèle
  • propriétés étendues au niveau du modèle

Le fait de ne pas suivre ces règles de retrait génère une erreur d’analyse.

Espace blanc

TMDL applique par défaut les règles suivantes aux espaces blancs dans les valeurs de propriété et d’expression, lorsqu’ils ne sont pas placés dans des backticks (```) ou des guillemets doubles (« ) :

  • Sur les valeurs de propriété, les espaces blancs de début et de fin sont supprimés.
  • Sur les expressions, les lignes d’espaces blancs à la fin des expressions sont supprimées.
  • Les lignes d’espaces blancs sont réduites en lignes vides (pas d’espaces/onglets).

Casse

Par défaut, l’API TMDL sur la sérialisation/écriture utilise camelCase, appliquée à :

  • Types d’objets
  • Mots clés
  • Valeurs d’énumération

Lors de la désérialisation/lecture, l’API TMDL ne respecte pas la casse.

Considérations et limitations

Maintenant que vous comprenez TMDL, consultez Prise en main de TMDL pour savoir comment obtenir et déployer une représentation de modèle TMDL d’un modèle Power BI.