Lenguaje de definición de modelo tabular (TMDL)

Se aplica a: SQL Server 2016 y versiones posteriores analysis Services Azure Analysis Services Fabric/Power BI Premium

Importante

El lenguaje de definición de modelos tabulares (TMDL) se encuentra actualmente en versión preliminar. Cuando se encuentra en versión preliminar, es probable que la funcionalidad y la documentación cambien.

Tabular Model Definition Language (TMDL) es una sintaxis de definición de modelo de objetos para modelos de datos tabulares en el nivel de compatibilidad 1200 o superior.

Entre los elementos clave de TMDL se incluyen:

  • Compatibilidad completa con todo el modelo de objetos tabulares (TOM). Cada objeto TMDL expone las mismas propiedades que TOM.
  • Basado en texto y optimizado para la interacción humana y la legibilidad. TMDL usa una sintaxis gramatical similar a YAML. Cada objeto TMDL se representa en texto con delimitadores mínimos y usa sangría para marcar las relaciones de elementos primarios y secundarios.
  • Mejor experiencia de edición, especialmente en propiedades con expresiones insertadas de diferentes tipos de contenido, como Expresión de análisis de datos (DAX) y M.
  • Mejor para la colaboración debido a su representación de carpeta en la que cada objeto de modelo tiene una representación de archivo individual, lo que hace que sea más fácil de usar el control de código fuente.

Un aspecto importante de TMDL es el uso de sangría de espacios en blanco para indicar una estructura de objetos TOM. En el ejemplo siguiente se muestra lo fácil que es representar un modelo tabular al usar 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]

Estructura de carpetas TMDL

A diferencia de TMSL, TMDL usa una estructura de carpetas. La estructura de carpetas predeterminada tiene solo un nivel de subcarpetas, todas con archivos .tmdl dentro de:

  • cultures
  • perspectivas
  • roles
  • Tablas

Y los archivos raíz para:

  • database
  • model
  • relationships
  • expresiones
  • datasources

Este es un ejemplo de una carpeta TMDL:

Carpeta con una representación TMDL de un modelo

Las definiciones incluyen:

  • Un archivo para la definición de base de datos.
  • Un archivo para la definición del modelo.
  • Un archivo para todos los orígenes de datos del modelo.
  • Un archivo para todas las expresiones del modelo.
  • Un archivo para todas las relaciones del modelo.
  • Un archivo para cada esquema lingüístico de referencia cultural.
  • Un archivo para cada perspectiva.
  • Un archivo para cada rol.
  • Un archivo para cada tabla.
  • Todas las propiedades de metadatos internas de las tablas (columna, jerarquías, particiones,...) residen en el archivo TMDL de la tabla primaria.

TMDL API

De forma similar al lenguaje de scripting de modelos tabulares (TMSL), hay una clase para controlar la serialización de TMDL. Para TMDL, la clase es TmdlSerializer, en el espacio de nombres Microsoft.AnalysisServices.Tabular .

La clase TmdlSerializer expone métodos para serializar y deserializar documentos TMDL:

Serialización de carpetas

public static void SerializeDatabaseToFolder (Database database, string path)

  • Recibe un objeto de base de datos TOM y la ruta de acceso de salida de TMDL.
  • Serializa la base de datos TOM en una representación de carpeta TMDL.

Obtenga más información sobre cómo serializar en una carpeta.

public static Database DeserializeDatabaseFromFolder (string path)

  • Recibe una ruta de acceso completa a una carpeta TMDL.
  • Devuelve la representación del objeto de base de datos TOM de la carpeta TMDL.

Obtenga más información sobre cómo deserializar desde carpetas.

Serialización de cadenas

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

  • Recibe un objeto TOM y devuelve su representación de texto TMDL.

Obtenga más información sobre cómo serializar un objeto en una cadena.

Serialización de secuencias

Puede serializar o deserializar TMDL a/desde secuencias, lo que le permite convertir un objeto TOM en flujos de bytes para almacenamiento, transmisión e interoperabilidad entre plataformas. Stream API también permite controlar qué documentos TMDL se cargan y qué documentos TMDL se generan.

La serialización de TMDL Stream se controla mediante la clase MetadataSerializationContext .

Obtenga más información sobre cómo serializar a/desde TMDL mediante secuencias.

Idioma TMDL

Declaración de objeto

Excepto para el objeto Server, TMDL expone todo el árbol de objetos de base de datos TOM en el espacio de nombres Microsoft.AnalysisServices.Tabular.

Un objeto TMDL se declara especificando el tipo de objeto TOM seguido de su nombre. En el ejemplo de código siguiente, cada tipo de objeto: model, tablecolumn , va seguido de un nombre de objeto.

model Model    
    culture: en-US    

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

    column 'Customer Key'
        datatype: int64
        sourceColumn: CustomerKey

Objetos como partition o measure tienen propiedades predeterminadas que se pueden asignar después del delimitador igual (=) en la misma línea de la declaración de objeto o en la siguiente línea para una expresión de varias líneas:

table Sales

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

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

El nombre del objeto TMDL debe incluirse entre comillas simples (') si incluye cualquiera de los caracteres siguientes:

  • Punto (.)
  • Igual a (=)
  • Dos puntos (:)
  • Comilla simple (')
  • Espacio en blanco ( )

Si un nombre de objeto contiene comillas simples ('), use dos comillas simples para escaparla.

Propiedades de objeto

Las propiedades de objeto se especifican después de la declaración de objeto o la expresión de varias líneas predeterminada del objeto. Los valores de propiedad de objeto se especifican siguiendo el delimitador de dos puntos (:). Por ejemplo:

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"

Las reglas siguientes se aplican a los valores de propiedad:

  • El valor debe estar en la misma línea después de los dos puntos y no puede tener varias líneas.

  • Valores de propiedad text

    • Las comillas dobles iniciales y finales son opcionales y se quitan automáticamente durante la serialización.
    • Debe ir entre comillas dobles (") si el texto contiene espacios en blanco finales o iniciales.
    • Cuando se incluye entre comillas dobles, si el valor contiene comillas dobles, use dos comillas dobles para escaparlas (vea displayFolder la propiedad en el ejemplo de código anterior).
  • Las propiedades booleanas se pueden establecer mediante la sintaxis de par clave-valor estándar, como con la 'isAvailableInMdx' propiedad del ejemplo anterior. También se pueden establecer mediante una sintaxis de método abreviado en la que solo se declara el nombre de la propiedad y true está implícito. Vea, por ejemplo, la propiedad 'isHidden' en el ejemplo anterior.

Referencias a objetos con nombre

Algunas propiedades de objeto contienen referencias a otros objetos de modelo, por ejemplo:

  • Referencia de columna en niveles de jerarquía.
  • referencia sortByColumn en cada columna de tabla.
  • Referencia de tabla,columna/medida en perspectivas.

En TMDL, las referencias se realizan con el nombre del objeto y siguen los mismos requisitos de escape y comillas simples (') envolventes de la declaración de objeto. En el ejemplo de código siguiente, verá propiedades de objeto que contienen una referencia a otro objeto: column.sortByColumn, perspectiveMeasure.measurelevel.columny perspectiveTable.table.


table Product

    column Category
        sortByColumn: 'Category Order'    

 hierarchy 'Product Hierarchy'

  level Category   
   column: Category  
 

perspective Product

 perspectiveTable Product

        perspectiveMeasure '# Products'

Si es necesario para hacer referencia a un nombre completo, TMDL usa la notación de puntos para hacer referencia a un objeto, por ejemplo: 'Table 1'.'Column 1'

Objetos secundarios

El árbol de objetos TOM contiene objetos secundarios en muchos lugares y en distintos niveles. Por ejemplo:

  • Un objeto de modelo contiene objetos de tabla, rol y expresión.
  • Un objeto table contiene objetos de columna, medida y jerarquía.

TMDL no declara colecciones secundarias explícitamente. En su lugar, todos los elementos secundarios aplicables dentro del ámbito de su elemento primario respectivo constituyen implícitamente los elementos de la colección correspondiente. Por ejemplo, todos los elementos de columna dentro del ámbito de una tabla determinada se convierten en elementos de la colección de columnas de esa tabla en TOM, como se muestra aquí:

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])    

Los objetos secundarios no tienen que ser contiguos. Por ejemplo, puede declarar columnas y medidas en cualquier orden e intercalación.

Propiedades predeterminadas

Algunos tipos de objeto tienen una propiedad predeterminada que la mayoría de las veces se tratan como expresiones. La propiedad predeterminada es específica del tipo de objeto. Si procede, el valor de propiedad o expresión se especifica después del delimitador igual (=) : después de la declaración de sección.

Sintaxis admitida:

  • El valor se especifica en la misma línea que el encabezado de sección.
  • El valor se especifica como una expresión de varias líneas después del encabezado de sección.

En el ejemplo de código siguiente, la medida Sales Amount y la partición Sales-Partition1 son una sola línea y la medida Quantity es de varias líneas:

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

Expresiones

Hay propiedades de objeto que, mientras se trata de una propiedad de texto en TOM, obtienen análisis especiales en TMDL. Todo el texto se lee textualmente porque puede incluir caracteres especiales como comillas o corchetes en expresiones M o DAX. Las expresiones pueden ser de varias líneas o de una sola línea. Si hay varias líneas, deben encontrarse en la línea inmediatamente después de la declaración de propiedad o objeto.

Se especifica un valor de expresión en TMDL siguiendo un delimitador igual (=), como en el ejemplo siguiente:

table Table1

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

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

Las siguientes reglas especiales se aplican a las expresiones:

  • Las expresiones de varias líneas deben aplicar sangría a un nivel más profundo a las propiedades del objeto primario y toda la expresión debe estar dentro de ese nivel de sangría.
  • Todos los espacios en blanco de sangría externa se quitan más allá del nivel de sangría del objeto primario.
  • Se permiten espacios en blanco verticales (líneas en blanco sin espacios en blanco) y se consideran parte de la expresión.
  • Se quitan las líneas en blanco finales y los espacios en blanco.
  • Para aplicar una sangría diferente o para conservar las líneas en blanco finales o espacios en blanco, use las tres ortografías inversas (```).
  • De forma predeterminada, el serializador TMDL se encierra con versos si el valor de expresión contiene algo que podría provocar una modificación en el recorrido de ida y vuelta (por ejemplo, espacios en blanco finales, líneas en blanco con espacios en blanco).

Las expresiones incluidas con tres acentos versos (```) son textuales de lectura, incluida la sangría, las líneas en blanco y los espacios en blanco. El delimitador se debe aplicar inmediatamente después del signo igual (=) y la línea que sigue a la expresión y no puede tener nada después, como en el ejemplo siguiente:

table Table1

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

            ```

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

El uso del delimitador de tres versos (```) es opcional y solo es necesario en situaciones únicas. En la mayoría de las situaciones, el uso de la sangría correcta y la declaración de objeto garantizan el análisis correcto de cualquier expresión que agregue a la propiedad .

Cuando la expresión se incluye dentro de las comillas inversas, se aplican las reglas siguientes:

  • Todo lo que hay entre tres acentos versos (```) se considera parte de la expresión de varios bloques y las reglas de sangría TMDL no se aplican. El delimitador final determina la sangría dentro de la expresión.
  • Se conserva la sangría relativa dentro de la expresión. El delimitador final (```) determina el límite izquierdo de la expresión (vea "Measure1" en el ejemplo anterior).

Las siguientes propiedades se tratan como expresiones:

Tipo de objeto Propiedad Lenguaje de expresiones
Medida Expresión DAX
MPartitionSource Expression M
CalculatedPartitionSource Expresión DAX
QueryPartitionSource Consultar NativeQuery
CalculationItem Expresión DAX
BasicRefreshPolicy SourceExpression, PollingExpression M
KPI StatusExpression, TargetExpression, TrendExpression DAX
LinguisticMetadata Contenido XML o Json
JsonExtendedProperty Valor Json
FormatStringDefintion Expresión DAX
DataCoverageDefinition Expresión DAX
CalculationGroupExpression Expresión DAX
NamedExpression Expresión DAX
DetailRowsDefinition Expresión DAX
TablePermission FilterExpression DAX
CalculatedColumn Expresión DAX

Propiedades predeterminadas por tipo de objeto

En la tabla siguiente se muestran la propiedad y el lenguaje de expresión predeterminados por tipo de objeto:

Tipo de objeto Propiedad predeterminada Lenguaje de expresiones
Medida Expresión DAX
CalculatedColumn Expresión DAX
CalculationItem Expresión DAX
FormatStringDefinition Expresión DAX
DetailRowsDefinition Expresión DAX
CalculationExpression Expresión DAX
DataCoverageDefinition Expresión DAX
TablePermission FilterExpression DAX
ColumnPermission MetadataPermission MetadataPermission Enum
NamedExpression Expression M
MPartitionSource Expression M
CalculatedPartitionSource Expresión DAX
JsonExtendedProperty Valor Json
Anotación Value Texto
StringExtendedProperty Valor Texto
DataSource Tipo Enumeración DataSourceType
Partition SourceType Enumeración PartitionSourceType
ChangedProperty Propiedad Texto de propiedad
ExternalModelRoleMember MemberType Enumeración RoleMemberType
Cualquier propiedad JSON personalizada (por ejemplo, DataAccessOptions) Documento JSON Json
LinguisticMetadata Contenido Json

Descripciones

TMDL proporciona compatibilidad de primera clase con descripciones. Para fines de documentación del modelo, el procedimiento recomendado es proporcionar descripciones para cada objeto TOM. TMDL trata las descripciones como una propiedad especial con compatibilidad con sintaxis explícita. Siguiendo los ejemplos de muchos otros lenguajes, las descripciones se especifican sobre cada declaración de objeto mediante la sintaxis de barra diagonal triple (///).

No se permite ningún espacio en blanco entre el extremo del bloque de descripción y el token de tipo de objeto.

Las descripciones se pueden dividir entre varias líneas. El serializador TMDL divide las descripciones del objeto en varias líneas para mantener las líneas de documento emitidas bajo la longitud máxima. La longitud máxima predeterminada es de 80 caracteres.

/// Table Description
table Sales

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

Declaración parcial

TMDL no fuerza la declaración de objeto en el mismo documento. Sin embargo, es similar a las clases parciales de C# donde es posible dividir la definición de objeto entre varios archivos. Por ejemplo, puede declarar una definición de tabla en un archivo [table].tmdl y, a continuación, tener todas las medidas de todas las tablas definidas en un único archivo [measures].tmdl, como se muestra aquí:

table Sales

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

table Product

    measure CountOfProduct = COUNTROWS(…)

Para evitar un error de análisis, la misma propiedad no se puede declarar dos veces. Por ejemplo, declarar dos medidas con el mismo nombre para la misma tabla en dos documentos TMDL diferentes produce un error.

Referencias a objetos

Puede hacer referencia a otro objeto TMDL mediante la palabra clave ref seguida del tipo de objeto y el nombre.

Por ejemplo, si serializa un objeto Column mediante la API de serialización de cadenas, el resultado será:

ref table Table1
	column Column1
		datatype: int64
		sourceColumn: Column1

Ordenación de colecciones deterministas

La palabra clave ref también se usa para definir y conservar el orden de recopilación en los recorridos de ida y vuelta de TOM <> TMDL. Es especialmente importante evitar diferencias de control de código fuente en objetos TMDL que se serializan en archivos individuales: tablas, roles, referencias culturales y perspectivas. La palabra clave ref se usa en el archivo TMDL del objeto primario para declarar la ordenación de elementos 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'

Se aplican las reglas siguientes:

  • Durante la deserialización de TMDL:
    • Se omiten los objetos a los que se hace referencia en TMDL, pero falta el archivo TMDL.
    • Los objetos no a los que se hace referencia, pero con el archivo TMDL existente, se anexan al final de la colección.
  • Durante la serialización de TMDL:
    • Se hace referencia a todos los objetos de colección de TOM mediante la palabra clave ref .
    • Las colecciones con un solo elemento no emiten una referencia.
    • Las líneas en blanco no se emiten entre ref si el mismo tipo de objeto.

Delimitadores de valor de propiedad

Solo hay dos delimitadores o símbolos para asignar un valor de propiedad:

  • Es igual a (=)

  • Dos puntos (:)

    • Se usa para cada valor de propiedad que no es de expresión. Incluir propiedades que contienen referencias de modelo.

Sangría

TMDL usa reglas estrictas de sangría de espacios en blanco para indicar la estructura de la jerarquía de TOM. Un documento TMDL usa una regla de sangría de tabulación única predeterminada.

Cada objeto puede tener tres niveles de sangría:

  • Nivel 1: declaración de objeto
    • Nivel 2: Propiedades del objeto
      • Nivel 3: expresiones de varias líneas de propiedad de objeto

Dentro de un documento TMDL, la sangría se aplica en los casos siguientes:

  • Entre un encabezado de sección de objeto y las propiedades del objeto (tabla :> propiedades).

    table Sales
        isHidden
        lineageTag: 9a48bea0-e5fb-40fa-9e81-f61288e31a02
    
  • Entre un objeto y sus objetos secundarios (tabla -> medidas).

    table Sales
    
        measure 'Sales Amount' = SUMX(...)
    
        measure 'Total Quantity' = SUM(...)
    
  • Entre un objeto y sus expresiones de varias líneas (tabla -> medida -> expresión).

    table Sales
    
        measure 'Sales Amount' = 
                var result = SUMX(...)
                return result
            formatString: $ #,##0
    
  • Las expresiones de varias líneas deben aplicar sangría a un nivel más profundo que las propiedades del objeto y toda la expresión debe estar dentro de ese nivel de sangría (vea expresiones).

No es necesario aplicar sangría a la base de datos ni a los objetos secundarios directos del modelo porque se asumen implícitamente anidados en el modelo raíz o la base de datos:

  • model
  • Tablas
  • expresiones compartidas
  • roles
  • cultures
  • perspectivas
  • relationships
  • orígenes de datos
  • consulta de grupos
  • anotaciones de nivel de modelo
  • propiedades extendidas de nivel de modelo

No seguir estas reglas de sangría genera un error de análisis.

Espacio en blanco

TMDL aplica de forma predeterminada las siguientes reglas a espacios en blanco dentro de los valores de propiedad y expresión, cuando no se incluyen entre comillas inversas (```) o comillas dobles ("):

  • En los valores de propiedad, se recortan los espacios en blanco iniciales y finales.
  • En las expresiones, se quitan las líneas de espacio en blanco al final de las expresiones.
  • Las líneas de espacio en blanco se recortan a líneas vacías (sin espacios o pestañas).

Uso de mayúsculas y minúsculas

De forma predeterminada, la API de TMDL en serialize/write usa camelCase, aplicada a:

  • Tipos de objeto
  • Palabras clave
  • Valores de enumeración

En la deserialización y lectura, TMDL API no distingue mayúsculas de minúsculas.

Consideraciones y limitaciones

Ahora que conoce TMDL, asegúrese de ver Introducción a TMDL para obtener información sobre cómo obtener e implementar una representación de modelo TMDL de un modelo semántico de Power BI.