使用表格式物件模型設計 Power BI 語意模型 (TOM)

適用於: SQL Server 2016 和更新版本的 Analysis Services Azure Analysis Services Fabric/Power BI Premium

本文最初是由Power BI客戶諮詢小組 (CAT) 針對 Power BI Dev Camp所建立,這是Power BI 進階程式設計的相關會話、文章和影片集合。

Power BI Premium 語意模型包含 XMLA 端點。 端點對 Power BI 開發人員很重要,因為它提供 API 來與 Power BI 服務中執行的 Analysis Services 引擎互動,並直接針對 Power BI 模型進行程式設計。 越來越多的 Power BI 專業人員發現,他們可以使用使用 SQL Server Management Studio、表格式編輯器和 DAX Studio 等 XMLA 通訊協定的既有工具來建立、檢視及管理 Power BI 模型。 身為 .NET 開發人員,您現在可以在 .NET 應用程式中撰寫 C# 程序代碼,直接在 Power BI 服務中建立和修改模型。

表格式物件模型 (TOM) 是 .NET 連結庫,提供 XMLA 端點頂端的抽象層。 它可讓開發人員以直覺式程序設計模型撰寫程序代碼,其中包含類別,例如 ModelTableColumnMeasure。 在幕後,TOM 會將程式代碼中的讀取和寫入作業轉譯成針對 XMLA 端點執行的 HTTP 要求。

要透過 XMLA 端點建立模型的應用程式圖表。

本文的重點在於開始使用 TOM,並示範如何在 Power BI 服務中執行時,撰寫建立和修改模型所需的 C# 程式代碼。 不過,TOM 也可用於不包含 XMLA 端點的案例,例如,針對在 Power BI Desktop 中執行的本機模型進行程式設計時。 若要深入瞭解如何搭配Power BI Desktop使用 TOM,請參閱 Power BI CAT 成員 Phil Seamark 的 部落格系列,並確定觀看如何使用表格式物件模型 (TOM) 影片中的 如何設計數據集。

TOM 代表 Power BI 開發人員的新且功能強大的 API,其與 Power BI REST API 不同。 雖然這兩個 API 之間有些重疊,但每個 API 都包含大量未包含在另一個 API 中的功能。 此外,有些案例需要開發人員同時使用這兩個 API 來實作完整的解決方案。

開始使用表格式物件模型

您必須先取得,才能使用 TOM 進行程式設計,這是工作區連線的 URL。 工作區連線 URL 會參考特定的工作區,並用來建立連接字串,讓您的程式代碼連線到該 Power BI 工作區,以及內部執行的模型。 首先,流覽至專用容量中執行之 Power BI 工作區的 [設定] 頁面。

[連結至工作區設定]。

注意

只有專用容量中執行的模型才支援 XMLA 端點。 它不適用於在共用容量中執行的模型。 如果使用 Power BI Premium per User 容量中的模型,您可以以使用者身分連線,但無法以服務主體身分連線。

流覽至 [ 設定] 窗格的 [Premium] 索引標籤后,請將 [工作區連線 URL] 複製到剪貼簿。

語意模型設定中的工作區連接字串。

下一個步驟是建立新的 .NET 應用程式,在其中撰寫使用 TOM 程式代碼的 C# 程序代碼。 您可以使用 .NET 5、.NET Core 3.1 或舊版在 .NET Framework 上建立 Web 應用程式或傳統型應用程式。 在本文中,我們會使用 .NET 5 SDK建立簡單的 C# 控制台應用程式。

建立新的主控台應用程式

首先,使用 .NET CLI 來建立新的控制台應用程式。

dotnet new console --name`

新增表格式物件模型 NuGet 套件

建立控制台應用程式之後,新增包含表格式物件模型 (TOM) 的 Microsoft.AnalysisServices.AdomdClient.NetCore.retail.amd64 NuGet 套件。 您可以使用下列 .NET CLI,在 .NET 5 應用程式中安裝套件:

dotnet add package Microsoft.AnalysisServices.NetCore.retail.amd64

新增連接字串

當您的專案已安裝 TOM 連結庫的 NuGet 套件時,您就可以使用 TOM 建立傳統的 Hello World 應用程式。 應用程式會使用工作區連線 URL 連接到 Power BI 工作區,然後透過工作區中的模型列舉,並在控制台視窗中顯示其名稱。

using System;
using Microsoft.AnalysisServices.Tabular;

class Program {
  static void Main() {

    // create the connect string
    string workspaceConnection = "powerbi://api.powerbi.com/v1.0/myorg/LearningTOM";
    string connectString = $"DataSource={workspaceConnection};";

    // connect to the Power BI workspace referenced in connect string
    Server server = new Server();
    server.Connect(connectString);

    // enumerate through models in workspace to display their names
    foreach (Database database in server.Databases) {
      Console.WriteLine(database.Name);
    }
  }
}

在此範例中,連接字串包含工作區連線 URL,但沒有使用者的相關信息。 如果您使用此程式碼執行主控台應用程式,應用程式將會開始執行,然後系統會提示您以瀏覽器為基礎的視窗登入。 如果您使用有權存取工作區連線 URL 所參考工作區的用戶帳戶登入,TOM 連結庫就能夠取得存取令牌、連線到 Power BI 服務,以及透過工作區中的模型列舉。

若要深入瞭解如何透過 XMLA 端點連線,請參閱 Sematic 模型與 XMLA 端點的連線 - 連線到進階工作區

使用使用者名稱和密碼進行驗證

針對安全性不重要的開發和測試案例,您可以硬式編碼您的使用者名稱和密碼,而不需要在每次執行程式以測試程序代碼時以互動方式登入,如下列程式代碼所示:

string workspaceConnection = "powerbi://api.powerbi.com/v1.0/myorg/YOUR_WORKSPACE";
string userId = "YOUR_USER_NAME";
string password = "YOUR_USER_PASSWORD";
string connectStringUser = $"DataSource={workspaceConnection};User ID={userId};Password={password};";
server.Connect(connectStringUser);

使用服務主體進行驗證

以服務主體而非使用者身分進行驗證也相當容易。 如果您已建立具有應用程式識別碼和應用程式密碼的 Microsoft Entra 應用程式,您可以使用下列程式代碼範例來驗證程式代碼,以作為 Microsoft Entra 應用程式的服務主體執行:

string workspaceConnection = "powerbi://api.powerbi.com/v1.0/myorg/YOUR_WORKSPACE";
string tenantId = "YOUR_TENANT_ID";
string appId = "YOUR_APP_ID";
string appSecret = "YOUR_APP_SECRET";
string connectStringApp = $"DataSource={workspaceConnection};User ID=app:{appId}@{tenantId};Password={appSecret};";
server.Connect(connectStringApp);

若要使用 TOM 進行程式設計並存取模型即服務主體,您必須在 Power BI 管理入口網站中設定租使用者層級的 Power BI 設定。 設定 Power BI 以支援以服務主體進行連線的步驟說明,使用服務主體內嵌 Power BI 內容,以及應用程式秘密

使用 Microsoft Entra 存取令牌進行驗證

TOM 也會在使用有效的Microsoft Entra 存取令牌建立連線時提供彈性。 如果您有使用 Microsoft Entra ID 實作驗證流程並取得存取令牌的開發人員技能,您可以格式化您的 TOM 連接字串,而不使用使用者名稱,但改為包含存取令牌作為密碼,如下列程式代碼範例所示:

public static void ConnectToPowerBIAsUser() {
  string workspaceConnection = "powerbi://api.powerbi.com/v1.0/myorg/YOUR_WORKSPACE";
  string accessToken = TokenManager.GetAccessToken();  // you must implement GetAccessToken yourself
  string connectStringUser = $"DataSource={workspaceConnection};Password={accessToken};";
  server.Connect(connectStringUser);
}

如果您要取得使用者型存取令牌以使用 TOM 連線到 Power BI 工作區,請務必在取得存取令牌時要求下列委派許可權,以確保您擁有您需要的所有撰寫許可權:

public static readonly string[] XmlaScopes = new string[] {
    "https://analysis.windows.net/powerbi/api/Content.Create",
    "https://analysis.windows.net/powerbi/api/Dataset.ReadWrite.All",
    "https://analysis.windows.net/powerbi/api/Workspace.ReadWrite.All",
};

如果您是使用 Power BI REST API 進行程式設計,您可能會辨識熟悉的許可權,例如 Content.CreateDataset.ReadWrite.AllWorkspace.ReadWrite.All。 有趣的觀察是,TOM 會使用與 https://analysis.windows.net/powerbi/apiMicrosoft Entra 資源標識符範圍內定義的 Power BI REST API 相同的委派許可權集。

XMLA 端點和 Power BI REST API 共用同一組委派許可權具有其優點的事實。 存取令牌可以在 TOM 與 Power BI REST API 之間交換使用。 取得存取令牌以呼叫 TOM 以建立新的模型之後,您可以使用相同的存取令牌來呼叫 Power BI REST API 來設定數據源認證,如本文稍後所述。

Power BI 程式設計人員通常會混淆的一件事是服務主體不會使用委派的許可權。 相反地,使用 TOM 進行程式設計時,您可以將它新增至目標工作區做為管理員或成員角色中的成員,來設定服務主體的存取權。

瞭解伺服器、資料庫和模型物件

TOM 中的物件模型是以具有最上層 Server 物件的階層為基礎,其中包含 database 物件的 集合。 在 Power BI 中使用 TOM 進行程式設計時,Server 物件代表 Power BI 工作區,而 Database 物件代表 Power BI 模型。

具有所有物件的表格式物件模型圖表

每個 資料庫 都包含一個 模型 物件,可提供數據模型的讀取/寫入存取權。 模型 包含數據模型專案的集合,包括 DataSource數據表關聯性檢視方塊文化特性Role

Hello World 程式代碼所示,一旦您呼叫 伺服器。連接,您可以透過 Server 物件的 Databases 集合,輕鬆地探索 Power BI 工作區中存在的模型,如下列程式代碼所示:

foreach (Database database in server.Databases) {
    Console.WriteLine(database.Name);
}

您也可以使用 Databases 集合對象公開的 GetByName 方法,依名稱存取模型,如下所示:

Database database = server.Databases.GetByName("Wingtip Sales");

請務必區分 Database物件及其內部 Model 屬性。 您可以使用 Database 物件屬性來探索模型屬性,例如 名稱識別子CompatibilityMode,以及 CompatibilityLevel。 另外還有一個 EstimatedSize 屬性,可讓您探索模型成長程度。 其他屬性包括 LastUpdateLastProcessed,以及 LastSchemaUpdate,可讓您判斷基礎模型上次重新整理的時間,以及上次更新模型架構的時間。

public static void GetDatabaseInfo(string DatabaseName) {
  Database database = server.Databases.GetByName(DatabaseName);
  Console.WriteLine("Name: " + database.Name);
  Console.WriteLine("ID: " + database.ID);
  Console.WriteLine("CompatibilityMode: " + database.CompatibilityMode);
  Console.WriteLine("CompatibilityLevel: " + database.CompatibilityLevel);
  Console.WriteLine("EstimatedSize: " + database.EstimatedSize);
  Console.WriteLine("LastUpdated: " + database.LastUpdate);
  Console.WriteLine("LastProcessed: " + database.LastProcessed);
  Console.WriteLine("LastSchemaUpdate: " + database.LastSchemaUpdate);
}

雖然 Database 物件有自己的屬性,但它是 Database 對象的內部 Model 物件,可讓您讀取和寫入模型的基礎數據模型。 以下是程式設計資料庫 Model 對象的簡單範例,以列舉其 Tables 集合,並探索數據表在內。

在 TOM 物件模型中,每個 Table 物件都有其分割區的集合物件。 數據行、量值和階層。

具有 Table、partition、column、measure 和 hierarchy 的表格式物件模型圖表

擷取 資料庫Model 對象之後,就可以使用 Tables 集合的 Find 方法,依名稱存取模型中的特定數據表。 以下是擷取名為 Sales數據表的範例,並透過 Columns 集合和 Measure 集合來探索其成員:

Model databaseModel = server.Databases.GetByName("Tom Demo").Model;

Table tableSales = databaseModel.Tables.Find("Sales");

foreach (Column column in tableSales.Columns) {
  Console.WriteLine("Coulumn: " + column.Name);
}

foreach (Measure measure in tableSales.Measures) {
  Console.WriteLine("Measure: " + measure.Name);
  Console.WriteLine(measure.Expression);
}

使用 TOM 修改模型

在上述各節中,您已瞭解如何存取 Database 物件及其 Model 物件,以檢查 Power BI 服務中執行之模型的數據模型。 現在是時候透過將量值新增至數據表,以程式設計第一個模型更新 TOM 了。

您使用的容量必須針對 XMLA 讀寫啟用 。 根據預設,XMLA 端點許可權設定為 讀取,因此必須明確設定為具有 Capacity Admin 許可權的人員 讀取寫入。 您可以在 管理入口網站中的 [容量設定] 頁面中檢視和更新此設定

管理入口網站中的 XMLA 讀取寫入設定。

當 XMLA 端點設定為讀寫時,您就可以將名為 Sales Revenue 的新量值新增至 Sales 數據表,如下列程式代碼所示:

Model dataset = server.Databases.GetByName("Tom Demo Starter").Model;
Table tableSales = dataset.Tables.Find("Sales");
Measure salesRevenue = new Measure();
salesRevenue.Name = "Sales Revenue";
salesRevenue.Expression = "SUM(Sales[SalesAmount])";
salesRevenue.FormatString = "$#,##0.00";
tableSales.Measures.Add(salesRevenue);
dataset.SaveChanges();

讓我們進一步瞭解此程序代碼。 首先,您會使用 C# 新的 運算符建立新的 Measure 物件,併為 NameExpressionFormatString提供值。 然後,藉由 呼叫 add 方法,將新的 Measure 物件新增至目標 Table 物件的 Measure 集合。 最後,呼叫 Model 物件的 SaveChanges 方法,將變更寫回 Power BI 服務中的模型。

請記住,模型更新會批處理在記憶體中,直到您呼叫saveChanges為止。 想像一下您想要隱藏數據表中每一個數據行的案例。 您可以從撰寫 foreach 迴圈 開始,以列舉數據表的所有 Column 物件,並將每個 Column 物件的 IsHidden 屬性設定為 true。 foreach 迴圈完成之後,您有數個數據行更新會批處理在記憶體中。 但最後呼叫 SaveChanges 會將所有變更推送回批次中的 Power BI 服務,如下所示:

Model dataset = server.Databases.GetByName("Tom Demo").Model;
Table tableSales = dataset.Tables.Find("Sales");

foreach (Column column in tableSales.Columns) {
  column.IsHidden = true;
}

dataset.SaveChanges();

假設您想要更新現有數據行的 FormatString 屬性。 Columns 集合會公開 Find 方法來擷取目標 Column 物件。 之後,只需要設定 FormatString 屬性,並呼叫 SaveChanges,如下所示:

Model dataset = server.Databases.GetByName("Tom Demo").Model;
Table tableSales = dataset.Tables.Find("Products");
Column columnListPrice = tableSales.Columns.Find("List Price");
columnListPrice.FormatString = "$#,##0.00";
dataset.SaveChanges();

TOM 能夠動態探索模型內的內容,可讓您以一般和全面的方式執行更新。 想像一下,您管理模型時,根據 DateTime 數據類型,擁有許多數據表和數百個數據行, 甚至數百個數據行。 您可以使用下列命令,更新整個模型中每個 DateTime 資料行的 FormatString 屬性:

Database database = server.Databases.GetByName("Tom Demo Starter");
Model datasetModel = database.Model;

foreach (Table table in datasetModel.Tables) {
  foreach (Column column in table.Columns) {
    if(column.DataType == DataType.DateTime) {
      column.FormatString = "yyyy-MM-dd";
    }
  }
}

datasetModel.SaveChanges();

使用 TOM 重新整理模型

現在讓我們執行一般模型維護作業。 如您在下列程式代碼中所見,使用 TOM 啟動模型重新整理作業並不十分複雜:

public static void RefreshDatabaseModel(string Name) {
  Database database = server.Databases.GetByName(Name);
  database.Model.RequestRefresh(RefreshType.DataOnly);
  database.Model.SaveChanges();
}

就像手動和排程的模型重新整理一樣,透過 XMLA 端點重新整理會顯示 重新整理歷程記錄,但使用卷標,透過 XMLA 端點

[重新整理歷程記錄] 對話框

注意

雖然 TOM 提供啟動重新整理作業的功能,但它無法為 Power BI 模型設定 數據源認證。 若要使用 TOM 重新整理模型,您必須先 語意模型設定 或使用 Power BI REST API 來設定數據源認證。

建立和複製模型

假設您需要使用以 C# 撰寫的程式代碼來建立和複製 Power BI 模型。 讓我們從撰寫名為 createDatabase 可重複使用的函式開始, 建立新的 Database 物件,如下所示:

public static Database CreateDatabase(string DatabaseName) {

  string newDatabaseName = server.Databases.GetNewName(DatabaseName);
  var database = new Database() {
    Name = newDatabaseName,
    ID = newDatabaseName,
    CompatibilityLevel = 1520,
    StorageEngineUsed = Microsoft.AnalysisServices.StorageEngineUsed.TabularMetadata,
    Model = new Model() {
      Name = DatabaseName + "-Model",
      Description = "A Demo Tabular data model with 1520 compatibility level."
    }
  };

  server.Databases.Add(database);
  database.Update(Microsoft.AnalysisServices.UpdateOptions.ExpandFull);
  return database;

}

在此範例中,我們將從 Databases 集合物件的 GetNewName方法開始,以確保我們的新模型名稱在目標工作區中是唯一的。 之後,Database 物件及其 Model 物件可以使用 C# 新的 運算符來建立,如下列程式代碼所示。 最後,這個方法會將新的 Database 物件新增至 Databases 集合,並呼叫 資料庫。更新 方法。

如果您的目標是複製現有的模型,而不是建立新的模型,您可以使用下列 CopyDatabase 方法來複製 Power BI 模型,方法是建立新的空白模型,然後在來源模型 Model 物件上呼叫 CopyTo,讓來源模型將整個數據模型複製到新建立的模型。

public static Database CopyDatabase(string sourceDatabaseName, string DatabaseName) {
  Database sourceDatabase = server.Databases.GetByName(sourceDatabaseName);
  string newDatabaseName = server.Databases.GetNewName(DatabaseName);
  Database targetDatabase = CreateDatabase(newDatabaseName);
  sourceDatabase.Model.CopyTo(targetDatabase.Model);
  targetDatabase.Model.SaveChanges();
  targetDatabase.Model.RequestRefresh(RefreshType.Full);
  targetDatabase.Model.SaveChanges();
  return targetDatabase;
}

從頭開始建立真實世界的模型

確定,現在假設您剛從頭開始建立新的模型,現在您需要使用 TOM 來新增數據表、數據行、量值、階層和數據表關聯性來撰寫真實世界的數據模型。 讓我們看看一個程式代碼範例,以建立包含已定義數據行的新數據表、新增三層維度階層,甚至提供基礎表查詢的 M 表達式:

private static Table CreateProductsTable() {

  Table productsTable = new Table() {
    Name = "Products",
    Description = "Products table",
    Partitions = {
      new Partition() {
        Name = "All Products",
        Mode = ModeType.Import,
        Source = new MPartitionSource() {
          // M code for query maintained in separate source file
          Expression = Properties.Resources.ProductQuery_m
        }
      }
    },
    Columns = {
      new DataColumn() { Name = "ProductId", DataType = DataType.Int64, SourceColumn = "ProductId", IsHidden = true },
      new DataColumn() { Name = "Product", DataType = DataType.String, SourceColumn = "Product" },
      new DataColumn() { Name = "Description", DataType = DataType.String, SourceColumn = "Description" },
      new DataColumn() { Name = "Category", DataType = DataType.String, SourceColumn = "Category" },
      new DataColumn() { Name = "Subcategory", DataType = DataType.String, SourceColumn = "Subcategory" },
      new DataColumn() { Name = "Product Image", DataType = DataType.String, 
                        SourceColumn = "ProductImageUrl", DataCategory = "ImageUrl" }
     }
  };

  productsTable.Hierarchies.Add(
    new Hierarchy() {
      Name = "Product Category",
      Levels = {
        new Level() { Ordinal=0, Name="Category", Column=productsTable.Columns["Category"] },
        new Level() { Ordinal=1, Name="Subcategory", Column=productsTable.Columns["Subcategory"] },
        new Level() { Ordinal=2, Name="Product", Column=productsTable.Columns["Product"] }
      }
  });

  return productsTable;
}

建立一組協助程式方法來建立數據表之後,您就可以將它們組合在一起以建立數據模型,如下所示:

Model model = database.Model;
Table tableCustomers = CreateCustomersTable();
Table tableProducts = CreateProductsTable();
Table tableSales = CreateSalesTable();
Table tableCalendar = CreateCalendarTable();
model.Tables.Add(tableCustomers);
model.Tables.Add(tableProducts);
model.Tables.Add(tableSales);
model.Tables.Add(tableCalendar);

TOM 會在 Model 對象上公開 關聯性 集合,讓您定義模型中數據表之間的關聯性。 以下是建立 SingleColumnRelationship 物件所需的程式代碼,它會建立 Products 數據表與 Sales 數據表之間的 一對多 關聯性:

model.Relationships.Add(new SingleColumnRelationship {
  Name = "Products to Sales",
  ToColumn = tableProducts.Columns["ProductId"],
  ToCardinality = RelationshipEndCardinality.One,
  FromColumn = tableSales.Columns["ProductId"],
  FromCardinality = RelationshipEndCardinality.Many
});

新增數據表和數據表關聯性之後,請使用呼叫 模型來儲存您的工作。SaveChanges

model.SaveChanges();

此時,呼叫 SaveChanges之後,您應該可以看到在 Power BI 服務中建立的新模型,並開始使用它來建立新的報表。

Power BI 服務中的模型報表。

重要

請記住,您必須在語意模型設定中或透過Power BI REST API 指定數據源認證,才能重新整理模型。

範例專案

本文中所見 C# 程式代碼的範例專案 在這裡。 現在,您現在可以開始使用 TOM 進行程式設計,並尋找在 Power BI 自定義解決方案開發中運用這個功能強大的新 API 的方法。

另請參閱

與 XMLA 端點的語意模型連線能力
XMLA 端點連線能力疑難解答