Partilhar via


TMDL (Tabular Model Definition Language)

aplica-se a: SQL Server 2016 e posteriores do Analysis Services Fabric/Power BI Premium do Azure Analysis Services

A TMDL (Tabular Model Definition Language) é uma sintaxe de definição de modelo de objeto para modelos de dados tabulares no nível de compatibilidade 1200 ou superior.

Os principais elementos do TMDL incluem:

  • Compatibilidade completa com todo otom (modelo de objeto de tabela) . Cada objeto TMDL expõe as mesmas propriedades que TOM.
  • Baseado em texto e otimizado para interação humana e legibilidade. O TMDL usa uma sintaxe gramatical semelhante ao YAML. Cada objeto TMDL é representado em texto com delimitadores mínimos e usa recuo para marcar relações pai-filho.
  • Melhor experiência de edição, especialmente em propriedades com expressões de inserção de diferentes tipos de conteúdo, como DAX (Expressão de Análise de Dados) e M.
  • Melhor para colaboração devido à representação de pasta em que cada objeto de modelo tem uma representação de arquivo individual, tornando-o mais amigável ao controle do código-fonte.

Um aspecto importante do TMDL é o uso do recuo de espaço em branco para indicar uma estrutura de objeto TOM. O exemplo a seguir mostra como é fácil representar um modelo de tabela ao 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]

Estrutura da pasta TMDL

Ao contrário do TMSL, o TMDL usa uma estrutura de pastas. A estrutura de pastas padrão tem apenas um nível de subpasta, tudo com arquivos .tmdl dentro:

  • Culturas
  • Perspectivas
  • Papéis
  • Tabelas

E arquivos raiz para:

  • base de dados
  • modelo
  • Relações
  • Expressões
  • fontes de dados

Aqui está um exemplo de uma pasta TMDL:

Pasta com uma representação TMDL de um modelo

As definições incluem:

  • Um arquivo para definição de banco de dados.
  • Um arquivo para definição de modelo.
  • Um arquivo para todas as fontes de dados no modelo.
  • Um arquivo para todas as expressões no modelo.
  • Um arquivo para todas as relações no modelo.
  • Um arquivo para cada esquema linguístico de cultura.
  • Um arquivo para cada perspectiva.
  • Um arquivo para cada função.
  • Um arquivo para cada tabela.
  • Todas as propriedades de metadados internos de tabelas (Coluna, Hierarquias, Partições,...) residem no arquivo TMDL da tabela pai.

TMDL API

Semelhante a TMSL (Tabular Model Scripting Language), há uma classe para lidar com a serialização TMDL. Para TMDL, a classe é TmdlSerializer, no namespace Microsoft.AnalysisServices.Tabular.

A classe TmdlSerializer expõe métodos para serializar e desserializar documentos TMDL:

Serialização de pasta

public static void SerializeDatabaseToFolder (Database database, string path)

  • Recebe um objeto de banco de dados TOM e o caminho de saída TMDL.
  • Serializa o banco de dados TOM em uma representação de pasta TMDL.

Saiba mais sobre como serializar para uma pasta.

public static Database DeserializeDatabaseFromFolder (string path)

  • Recebe um caminho completo para uma pasta TMDL.
  • Retorna a representação do objeto de banco de dados TOM da pasta TMDL.

Saiba mais sobre como desserializar de pastas.

Serialização de cadeia de caracteres

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

  • Recebe um objeto TOM e retorna sua representação de texto TMDL.

Saiba mais sobre como serializar um objeto em uma cadeia de caracteres.

Serialização de fluxo

Você pode serializar/desserializar o TMDL de/para fluxos, permitindo converter um objeto TOM em fluxos de bytes para armazenamento, transmissão e interoperabilidade entre plataformas. A API do Stream também permite controlar quais documentos TMDL são carregados e quais documentos TMDL são gerados.

A serialização do Fluxo de TMDL é tratada pela classe MetadataSerializationContext.

Saiba mais sobre como serializar de/para TMDL usando fluxos.

Idioma TMDL

Declaração de objeto

Com exceção do objeto Server, o TMDL expõe toda a árvore de objetos banco de dados TOM no namespace Microsoft.AnalysisServices.Tabular.

Um objeto TMDL é declarado especificando o tipo de objeto TOM seguido pelo nome. No exemplo de código a seguir, cada tipo de objeto: model, table, column é seguido por um nome de objeto.

model Model    
    culture: en-US    

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

    column 'Customer Key'
        datatype: int64
        sourceColumn: CustomerKey

Objetos como partition ou measure têm propriedades padrão que podem ser atribuídas após o delimitador igual (=) na mesma linha da declaração de objeto ou na seguinte linha para uma expressão de de várias linhas:

table Sales

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

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

O nome do objeto TMDL deve ser colocado entre aspas simples (') se ele incluir qualquer um dos seguintes caracteres:

  • Dot (.)
  • Iguais (=)
  • Dois-pontos (:)
  • Aspa única (')
  • Espaço em branco ( )

Se um nome de objeto contiver aspas simples ('), use duas aspas simples para escapar dele.

Propriedades do objeto

As propriedades do objeto são especificadas após a declaração de objeto ou a expressão de várias linhas da propriedade padrão do objeto. Os valores da propriedade do objeto são especificados seguindo o delimitador dois-pontos (:). Por exemplo:

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"

As regras a seguir se aplicam aos valores de propriedade:

  • O valor deve estar na mesma linha seguindo os dois-pontos e não pode ter várias linhas.

  • Valores de propriedade de texto

    • As aspas duplas à esquerda e à direita são opcionais e removidas automaticamente durante a serialização.
    • Deve estar entre aspas duplas (") se o texto contiver espaço em branco à direita ou à esquerda.
    • Quando colocado entre aspas duplas, se o valor contiver aspas duplas, use duas aspas duplas para escape delas (consulte displayFolder propriedade no exemplo de código acima).
  • propriedades boolianas podem ser definidas usando a sintaxe de par chave/valor padrão, como com a propriedade 'isAvailableInMdx' no exemplo anterior. Eles também podem ser definidos usando uma sintaxe de atalho em que apenas o nome da propriedade é declarado e true está implícito. Veja, por exemplo, a propriedade 'isHidden' no exemplo anterior.

Referências de objeto nomeado

Algumas propriedades de objeto contêm referências a outros objetos de modelo, por exemplo:

  • Referência de coluna em níveis de hierarquia.
  • Referência sortByColumn em cada coluna de tabela.
  • Referência de tabela/coluna/medida em perspectivas.

No TMDL, as referências são feitas usando o nome do objeto e seguem os mesmos requisitos de escape e aspas simples (') que incluem os requisitos da declaração de objeto. No exemplo de código a seguir, você verá propriedades de objeto que contêm uma referência a outro objeto: column.sortByColumn, level.column, perspectiveMeasure.measure e perspectiveTable.table.


table Product

    column Category
        sortByColumn: 'Category Order'    

 hierarchy 'Product Hierarchy'

  level Category   
   column: Category  
 

perspective Product

 perspectiveTable Product

        perspectiveMeasure '# Products'

Se necessário para fazer referência a um nome totalmente qualificado, o TMDL usará notação ponto para fazer referência a um objeto, por exemplo: 'Table 1'.'Column 1'

Objetos filho

A árvore de objetos TOM contém objetos filho em muitos locais e em níveis diferentes. Por exemplo:

  • Um objeto de modelo contém objetos de tabela, função e expressão.
  • Um objeto de tabela contém objetos de coluna, medida e hierarquia.

O TMDL não declara coleções filho explicitamente. Em vez disso, todos os elementos filho aplicáveis no escopo de seu respectivo pai compõem implicitamente os elementos da coleção correspondente. Por exemplo, todos os elementos de coluna dentro do escopo de uma tabela específica tornam-se elementos da coleção de colunas dessa tabela no TOM, como mostrado aqui:

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

Objetos filho não precisam ser contíguos. Por exemplo, você pode declarar colunas e medidas em qualquer ordem e interminge.

Propriedades padrão

Alguns tipos de objeto têm uma propriedade padrão que, na maioria das vezes, são tratadas como expressões . A propriedade padrão é específica do tipo de objeto. Quando aplicável, o valor da propriedade ou expressão é especificado seguindo o delimitador igual (=) após a declaração da seção.

Sintaxe com suporte:

  • O valor é especificado na mesma linha que o cabeçalho da seção.
  • O valor é especificado como uma expressão de várias linhas após o cabeçalho da seção.

No exemplo de código a seguir, Sales Amount de medida e Sales-Partition1 de partição são de linha única e Quantity de medida é de várias linhas:

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

Expressões

Há propriedades de objeto que, embora sejam uma propriedade de texto no TOM, obtenham análise especial no TMDL. O texto inteiro é lido verbatim porque pode incluir caracteres especiais, como aspas ou colchetes em expressões M ou DAX. Expressões podem ser de várias linhas ou de linha única. Se houver várias linhas, elas deverão estar localizadas na linha imediatamente após a declaração de propriedade ou objeto.

Um valor de expressão em TMDL é especificado seguindo um delimitador igual (=), como no exemplo a seguir:

table Table1

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

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

As seguintes regras especiais se aplicam a expressões:

  • Expressões de várias linhas devem ser recuadas um nível mais profundo para as propriedades do objeto pai e toda a expressão deve estar dentro desse nível de recuo.
  • Todos os espaços em branco de recuo externo são removidos além do nível recuado do objeto pai.
  • Espaços em branco verticais (linhas em branco sem espaços em branco) são permitidos e são considerados parte da expressão.
  • Linhas em branco à direita e espaços em branco são removidos.
  • Para impor um recuo diferente ou preservar linhas em branco ou espaços em branco à direita, use os três backticks (```) delimitantes.
  • Por padrão, o serializador TMDL será colocado com backticks se o valor da expressão contiver qualquer coisa que possa causar uma modificação na ida e volta (por exemplo, espaços em branco à direita, linhas em branco com espaços em branco).

Expressões entre três backticks (```) são lidas verbatim, incluindo recuo, linhas em branco e espaços em branco. O delimitador deve ser aplicado imediatamente após o sinal de igual (=) e a linha que segue a expressão e não pode ter nada depois dela, como no exemplo a seguir:

table Table1

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

            ```

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

Usar o delimitador de três backticks (```) é opcional e necessário apenas em situações exclusivas. Para a maioria das situações, usar o recuo correto e a declaração de objeto garante a análise correta de qualquer expressão que você adicionar à propriedade.

Quando a expressão é colocada entre backticks, as seguintes regras se aplicam:

  • Tudo entre três backticks (```) é considerado parte da expressão de vários blocos e as regras de recuo de TMDL não são aplicadas. O delimitador final determina o recuo dentro da expressão.
  • O recuo relativo dentro da expressão é mantido. O delimitador final (```) determina o limite esquerdo da expressão (consulte 'Measure1' no exemplo anterior).

As seguintes propriedades são tratadas como expressões:

Tipo de objeto Propriedade Linguagem de expressão
Medir Expressão DAX
MPartitionSource Expressão M
CalculatedPartitionSource Expressão DAX
QueryPartitionSource Consulta NativeQuery
CalculationItem Expressão DAX
BasicRefreshPolicy SourceExpression, PollingExpression M
KPI StatusExpression, TargetExpression, TrendExpression DAX
LinguisticMetadata Conteúdo XML ou Json
JsonExtendedProperty Valor Json
FormatStringDefintion Expressão DAX
DataCoverageDefinition Expressão DAX
CalculationGroupExpression Expressão DAX
NamedExpression Expressão DAX
DetailRowsDefinition Expressão DAX
TablePermission FilterExpression DAX
CalculatedColumn Expressão DAX

Propriedades padrão por tipo de objeto

A tabela a seguir mostra a propriedade padrão e a linguagem de expressão por tipo de objeto:

Tipo de objeto Propriedade padrão Linguagem de expressão
Medir Expressão DAX
CalculatedColumn Expressão DAX
CalculationItem Expressão DAX
FormatStringDefinition Expressão DAX
DetailRowsDefinition Expressão DAX
CalculationExpression Expressão DAX
DataCoverageDefinition Expressão DAX
TablePermission FilterExpression DAX
ColumnPermission MetadataPermission Enumeração metadataPermission
NamedExpression Expressão M
MPartitionSource Expressão M
CalculatedPartitionSource Expressão DAX
JsonExtendedProperty Valor Json
Anotação Valor Texto
StringExtendedProperty Valor Texto
DataSource Tipo Enumeração DataSourceType
Partição SourceType Enumeração PartitionSourceType
ChangedProperty Propriedade de texto da propriedade
ExternalModelRoleMember MemberType de Enumeração RoleMemberType
Qualquer propriedade JSON personalizada (por exemplo, DataAccessOptions) Documento JSON Json
LinguisticMetadata Conteúdo Json

Descrições

O TMDL fornece suporte de primeira classe para descrições. Para fins de documentação de modelo, a melhor prática é fornecer descrições para cada objeto TOM. O TMDL trata as descrições como uma propriedade especial com suporte explícito à sintaxe. Seguindo os exemplos de vários outros idiomas, as descrições são especificadas sobre cada declaração de objeto usando a sintaxe de barra tripla (///).

Nenhum espaço em branco é permitido entre o fim do bloco de descrição e o token de tipo de objeto.

As descrições podem ser divididas entre várias linhas. O serializador TMDL quebra descrições de objeto em várias linhas para manter as linhas de documento emitidas sob o comprimento máximo. O comprimento máximo padrão é de 80 caracteres.

/// Table Description
table Sales

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

Declaração parcial

O TMDL não força a declaração de objeto no mesmo documento. No entanto, é semelhante a classes parciais do C# em que é possível dividir a definição de objeto entre vários arquivos. Por exemplo, você pode declarar uma definição de tabela em um arquivo [table].tmdl e, em seguida, ter todas as medidas de todas as tabelas definidas em um único arquivo [measures].tmdl, conforme mostrado aqui:

table Sales

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

table Product

    measure CountOfProduct = COUNTROWS(…)

Para evitar um erro de análise, a mesma propriedade não pode ser declarada duas vezes. Por exemplo, declarar duas medidas com o mesmo nome para a mesma tabela em dois documentos TMDL diferentes resulta em um erro.

Referências de objeto

Você pode referenciar outro objeto TMDL usando a palavra-chave ref seguida pelo nome e o tipo de objeto.

Por exemplo, se você serializar um objeto Column usando a API de serialização de cadeia de caracteres, o resultado será:

ref table Table1
	column Column1
		datatype: int64
		sourceColumn: Column1

Ordenação de coleção determinística

A palavra-chave ref também é usada para definir e preservar a ordenação da coleção em viagens de ida e volta do TOM <> TMDL. É particularmente importante evitar diferenças de controle do código-fonte em objetos TMDL que são serializados em arquivos individuais: Tabelas, Funções, Culturas e Perspectivas. A palavra-chave ref é usada no arquivo TMDL do objeto pai para declarar a ordenação de item 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'

As seguintes regras são aplicadas:

  • Durante a Desserialização do TMDL:
    • Os objetos referenciados no TMDL, mas com o arquivo TMDL ausente, são ignorados.
    • Objetos não referenciados, mas com o arquivo TMDL existente, são acrescentados ao final da coleção.
  • Durante a serialização TMDL:
    • Todos os objetos de coleção no TOM são referenciados usando a palavra-chave ref.
    • Coleções com apenas um item não emitem um ref.
    • Linhas em branco não são emitidas entre ref's se o mesmo tipo de objeto.

Delimitadores de valor da propriedade

Há apenas dois delimitadores/símbolos para atribuir um valor de propriedade:

  • Iguais (=)

    • Usado na declaração de objeto com propriedade padrão (linha múltipla e única)
    • Usado em cada propriedade de expressão , por exemplo, partition.expression
  • Dois-pontos (:)

    • Usado para cada valor de propriedade não expressão. Incluindo propriedades que contêm referências de modelo.

Indentação

O TMDL usa regras de recuo de espaço em branco estritas para denotar a estrutura da hierarquia TOM. Um documento TMDL usa uma guia de única padrão regra de recuo.

Cada objeto pode ter três níveis de recuo:

  • Nível 1 – Declaração de Objeto
    • Nível 2 – Propriedades do objeto
      • Nível 3 – Expressões de várias linhas da propriedade object

Em um documento TMDL, o recuo é aplicado nos seguintes casos:

  • Entre um cabeçalho de seção de objeto e as propriedades do objeto (tabela –> propriedades).

    table Sales
        isHidden
        lineageTag: 9a48bea0-e5fb-40fa-9e81-f61288e31a02
    
  • Entre um objeto e seus objetos filho (tabela –> medidas).

    table Sales
    
        measure 'Sales Amount' = SUMX(...)
    
        measure 'Total Quantity' = SUM(...)
    
  • Entre um objeto e suas expressões de várias linhas (tabela -> medida -> expressão).

    table Sales
    
        measure 'Sales Amount' = 
                var result = SUMX(...)
                return result
            formatString: $ #,##0
    
  • Expressões de várias linhas devem ser recuadas em um nível mais profundo do que as propriedades do objeto e a expressão inteira deve estar dentro desse nível de recuo (consulte expressões).

O banco de dados e os objetos filho diretos do Modelo não precisam ser recuados porque são implicitamente assumidos aninhados no modelo raiz ou no banco de dados:

  • modelo
  • Tabelas
  • expressões compartilhadas
  • Papéis
  • Culturas
  • Perspectivas
  • Relações
  • fontes de dados
  • grupos de consulta
  • anotações no nível do modelo
  • propriedades estendidas no nível do modelo

Não seguir essas regras de recuo gera um erro de análise.

Whitespace

Por padrão, o TMDL aplica as seguintes regras ao espaço em branco dentro de valores de propriedade e expressão, quando não entre backticks (```) ou aspas duplas ("):

  • Em valores de propriedade, os espaços em branco à esquerda e à direita são cortados.
  • Em expressões, as linhas de espaço em branco no final das expressões são descartadas.
  • As linhas de espaço em branco são cortadas em linhas vazias (sem espaços/guias).

Caixa

Por padrão, a API TMDL no uso de serialização/gravação camelCase, aplicada a:

  • Tipos de objeto
  • Keywords
  • Enumerar valores

Ao desserializar/ler, a API TMDL não diferencia maiúsculas de minúsculas.

Agora que você tem uma compreensão do TMDL, certifique-se de ver Introdução ao TMDL para saber como obter e implantar uma representação de modelo TMDL de um modelo semântico do Power BI.