TMDL 시작

적용 대상: SQL Server 2016 이상 Analysis Services Azure Analysis Services Fabric/Power BI Premium

중요

TMDL(테이블 형식 모델 정의 언어)은 현재 미리 보기로 제공됩니다. 미리 보기 단계에서는 기능 및 설명서가 변경될 수 있습니다.

이 문서를 시작하기 전에 TMDL(테이블 형식 모델 정의 언어) 개요에 설명된 개념을 철저히 이해해야 합니다.

TMDL을 탐색하는 가장 쉬운 방법은 AMO(Analysis Services Management Objects) Nuget 패키지를 참조하고 TMDL API 메서드를 사용하여 TMDL 간 직렬화 및 역직렬화하는 것입니다.

Nuget 패키지 가져오기

TMDL 모델 표현 가져오기

다음 코드 예제에서는 Power BI Premium 작업 영역에서 의미 체계 모델의 TMDL 모델 표현을 가져오는 방법을 보여줍니다.

var workspaceXmla = " <Workspace XMLA address>";
var datasetName = "<dataset name>";
var outputPath = System.Environment.CurrentDirectory;

using (var server = new Server())
{
    server.Connect(workspaceXmla);

    var database = server.Databases.GetByName(datasetName);

    var destinationFolder = $"{outputPath}\\{database.Name}-tmdl";

    TmdlSerializer.SerializeDatabaseToFolder(database.Model, destinationFolder);

}

출력은 다음과 같이 모델의 TMDL 표현이 있는 폴더입니다.

모델의 TMDL 표현이 있는 폴더

폴더로 serialization한 후 텍스트 편집기를 사용하여 TMDL 파일을 편집합니다. 예를 들어 Visual Studio Code 사용하여 새 측정값인 [판매액(컴퓨터)]을 추가할 수 있습니다.

/// Sales data for year over year analysis
table Sales        

    partition 'Sales-Part1' = m
        mode: Import        
        source =
            let
                …
            in
                #"Filtered Rows1"

    measure 'Sales Amount' = SUMX('Sales', [Quantity] * [Net Price])
        formatString: $ #,##0

    measure 'Sales Amount (Computers)' = CALCULATE([Sales Amount], 'Product'[Category] = "Computers")
        formatString: $ #,##0

더 나은 환경을 위해 Visual Studio Code TMDL 언어 확장을 설치할 수 있습니다.

TMDL 모델 표현 배포

다음 코드 예제에서는 모델의 TMDL 모델 표현을 Power BI Premium 작업 영역에 배포하는 방법을 보여줍니다.

var xmlaServer = "<Workspace XMLA address>";

var tmdlFolderPath = $"{System.Environment.CurrentDirectory}\\Contoso-tmdl";

var model = TmdlSerializer.DeserializeDatabaseFromFolder(tmdlFolderPath);            

using (var server = new Server())
{
    server.Connect(xmlaServer);

    using (var remoteDatabase = server.Databases[model.Database.ID])
    {
        model.CopyTo(remoteDatabase.Model);

        remoteDatabase.Model.SaveChanges();
    }               
}

실행되면 새 측정값이 모델에 배포됩니다.

데이터 세트의 판매액(컴퓨터) 측정값

TMDL serialization 오류 처리

TMDL serialization 메서드에서 오류가 검색되면 및 InvalidOperationException와 같은 ArgumentException 몇 가지 일반적인 .NET 예외를 throw하는 것 외에 TMDL 관련 예외도 반환됩니다.

  • TmdlFormatException TMDL 텍스트가 유효한 구문이 아닌 경우 throw됩니다. 예를 들어 잘못된 키워드(keyword) 들여쓰기입니다.

  • TmdlSerializationException 는 TMDL 텍스트가 유효하지만 TOM 메타데이터 논리를 위반하는 경우 throw됩니다. 예를 들어 값 형식이 예상 형식과 일치하지 않습니다.

예외 세부 정보 외에도 다음이 포함됩니다.

  • document path: 오류가 있는 TMDL 파일의 경로입니다.
  • line number: 오류가 있는 줄 번호입니다.
  • line text: 오류가 있는 줄 텍스트입니다.

코드 예제 처리 TmdlFormatException:

try
{
    var tmdlPath = "<TMDL Folder Path>";

    var model = TmdlSerializer.DeserializeDatabaseFromFolder(tmdlPath);
}
catch (TmdlFormatException ex)
{
    Console.WriteLine($"Error on Deserializing TMDL '{ex.Message}', document path: '{ex.Document}'  line number: '{ex.Line}', line text: '{ex.LineText}'");

    throw;
}    

개체 텍스트 serialization

다음 코드 예제에서는 열을 TMDL로 serialize하는 방법을 보여줍니다.


var output = TmdlSerializer.SerializeObject(model.Tables["Product"].Columns["ProductKey"], qualifyObject: true);

Console.WriteLine(output);

출력:

ref table Product

 column ProductKey
  dataType: int64
  isKey
  formatString: 0
  isAvailableInMdx: false
  lineageTag: 4184d53e-cd2d-4cbe-b8cb-04c72a750bc4
  summarizeBy: none
  sourceColumn: ProductKey

  annotation SummarizationSetBy = Automatic

serialization 스트리밍

다음 코드 예제에서는 의미 체계 모델을 단일 텍스트 변수로 serialize하는 방법을 보여줍니다.

var output = new StringBuilder();

foreach (MetadataDocument document in model.ToTmdl())
{
    using (TextWriter writer = new StringWriter(output))
    {
        document.WriteTo(writer);
    }
}

Console.WriteLine(output.ToString());

다음 코드 예제에서는 역할을 제외한 TMDL에서 역직렬화하는 방법을 보여 줍니다.

var context = MetadataSerializationContext.Create(MetadataSerializationStyle.Tmdl);

var files = Directory.GetFiles("[TMDL Directory Path]", "*.tmdl", SearchOption.AllDirectories);

foreach (var file in files)
{
    if (file.Contains("/roles/"))
        continue;

    using (TextReader reader = File.OpenText(file))
    {                    
        context.ReadFromDocument(file, reader);
    }
}

var model = context.ToModel();