以 F# 開始使用 Azure 資料表儲存體和 Azure Cosmos DB 資料表 API

Azure 資料表儲存體是可將結構化的 NoSQL 資料儲存在雲端中的服務。 資料表儲存體是具有無結構描述設計的索引鍵/屬性存放區。 由於表格儲存體並無結構描述,因此可輕鬆地視應用程式發展需求改寫資料。 針對各種類的應用程式來存取資料都非常快速且符合經濟效益。 以類似的資料量來說,資料表儲存體的成本通常比傳統 SQL 低得許多。

您可以使用資料表儲存體來儲存彈性資料集,例如 Web 應用程式的使用者資料、通訊錄、裝置資訊,以及服務所需的任何其他型別中繼資料。 您可以在資料表中儲存任意數目的實體,且儲存體帳戶可包含任意數目的資料表,最高可達儲存體帳戶的容量上限。

Azure Cosmos DB 提供的資料表 API 適用於針對 Azure 資料表儲存體所撰寫、且需要進階功能的應用程式,例如:

  • 加值型全域分散。
  • 全球專用輸送量。
  • 第 99 個百分位數的個位數毫秒延遲。
  • 保證高可用性。
  • 自動進行次要編製索引。

針對 Azure 資料表儲存體所撰寫的應用程式可使用資料表 API (不變更程式碼) 來移轉至 Azure Cosmos DB,並且利用進階功能。 資料表 API 具有適用於 .NETJAVAPythonNode.js 的用戶端 SDK。

如需詳細資訊,請參閱 Azure Cosmos DB 資料表 API 簡介

關於本教學課程

本教學課程示範如何使用 Azure 資料表儲存體或 Azure Cosmos DB 資料表 API 來撰寫 F# 程式碼以執行一些常見工作,包括建立和刪除資料表,以及插入、更新、刪除和查詢資料表資料。

必要條件

若要使用本指南,您必須先建立 Azure 儲存體帳戶Azure Cosmos DB 帳戶

建立 F# 指令碼並啟動 F# 互動

本文中的範例可用於 F# 應用程式或 F# 指令碼。 若要建立 F# 指令碼,請在 F# 開發環境中建立副檔名為 .fsx 的檔案,例如 tables.fsx

如何執行指令碼

F# 互動 dotnet fsi 可透過互動方式啟動,也可從命令列中啟動以執行指令碼。 命令列語法為

> dotnet fsi [options] [ script-file [arguments] ]

在指令碼中新增封裝

接下來,使用 #rnuget:package name 來安裝 Azure.Data.Tables 封裝和 open 命名空間。 例如

> #r "nuget: Azure.Data.Tables"
open Azure.Data.Tables

新增命名空間宣告

tables.fsx 檔案最上方加入下列 open 陳述式:

open System
open Azure
open Azure.Data.Tables // Namespace for Table storage types

取得 Azure 儲存體連接字串

如果您要連線到 Azure 儲存體資料表服務,便需要此教學課程的連接字串。 您可以從 Azure 入口網站複製連接字串。 如需連接字串的詳細資訊,請參閱設定儲存體連接字串

取得 Azure Cosmos DB 連接字串

如果您要連線到 Azure Cosmos DB,便需要此教學課程的連接字串。 您可以從 Azure 入口網站複製連接字串。 在 Azure 入口網站的 Cosmos DB 帳戶中,移至 [設定]>[連接字串],然後選取 [複製] 按鈕以複製主要連接字串。

在本教學課程中,於指令碼內輸入連接字串,如下列範例所示:

let storageConnString = "UseDevelopmentStorage=true" // fill this in from your storage account

建立資料表服務用戶端

TableServiceClient 類別可讓您擷取資料表儲存體中的資料表和實體。 以下為建立服務用戶端的一種方式:

let tableClient = TableServiceClient storageConnString

您現在已準備好撰寫程式碼,以自資料表儲存體讀取資料並將資料寫入其中。

建立表格

此範例說明如何建立尚不存在的資料表:

// Retrieve a reference to the table.
let table = tableClient.GetTableClient "people"

// Create the table if it doesn't exist.
table.CreateIfNotExists () |> ignore

將實體新增至資料表

實體必須有實作 ITableEntity 的類型。 您可以用任何方式擴充 ITableEntity,但類型必須具有無參數建構函式。 只有同時具有 getset 的屬性會儲存在 Azure 資料表中。

實體的資料分割索引鍵和資料列索引鍵可唯一識別資料表中的實體。 比起具有不同分割索引鍵的實體,您可以更快查詢具有相同分割索引鍵的實體,但使用不同的分割索引鍵可提升平行作業的可擴縮性。

以下是 Customer 的範例,此範例以 lastName 作為資料分割索引鍵,並以 firstName 作為資料列索引鍵。

type Customer (firstName, lastName, email: string, phone: string) =
    interface ITableEntity with
        member val ETag = ETag "" with get, set
        member val PartitionKey = "" with get, set
        member val RowKey = "" with get, set
        member val Timestamp = Nullable() with get, set

    new() = Customer(null, null, null, null)
    member val Email = email with get, set
    member val PhoneNumber = phone with get, set
    member val PartitionKey = lastName with get, set
    member val RowKey = firstName with get, set

現在,將 Customer 新增至資料表。 若要這樣做,我們可以使用 AddEntity() 方法。

let customer = Customer ("Walter", "Harp", "Walter@contoso.com", "425-555-0101")
table.AddEntity customer

插入一批實體

您可以使用單一寫入作業,將一批實體插入至資料表。 批次作業可讓您將作業合併為單一執行,但有一些限制:

  • 您可以在同一批次作業中執行更新、刪除和插入。
  • 批次作業最多可包含 100 個實體。
  • 批次作業中的所有實體必須具有相同的資料分割索引鍵。
  • 雖然可以在批次作業中執行查詢,但該查詢必須是批次中的唯一作業。

以下是將兩個插入合併為批次作業的程式碼:

let customers =
    [
        Customer("Jeff", "Smith", "Jeff@contoso.com", "425-555-0102")
        Customer("Ben", "Smith", "Ben@contoso.com", "425-555-0103")
    ]

// Add the entities to be added to the batch and submit it in a transaction.
customers
|> List.map (fun customer -> TableTransactionAction (TableTransactionActionType.Add, customer))
|> table.SubmitTransaction

擷取分割中的所有實體

若要查詢分割中所有實體的資料表,請使用 Query<T> 物件。 在這裡,您會篩選「Smith」是資料分割索引鍵的實體。

table.Query<Customer> "PartitionKey eq 'Smith'"

擷取分割中某範圍的實體

如果您不想查詢分割中的所有實體,可以結合分割索引鍵篩選與資料列索引鍵篩選來指定範圍。 在這裡,您會使用兩個篩選來取得「Smith」資料分割中,資料列索引鍵 (名字) 開頭的字母在字母「M」之前的所有實體。

table.Query<Customer> "PartitionKey eq 'Smith' and RowKey lt 'J'"

擷取單一實體

若要擷取單一特定實體,請使用 GetEntityAsync 來指定客戶「Ben Smith」。 您收到的不會是集合,而是 Customer。 若要從資料表服務中擷取單一實體,最快的方法是在查詢中同時指定資料分割索引鍵和資料列索引鍵。

let singleResult = table.GetEntity<Customer>("Smith", "Ben").Value

您現在列印結果:

// Evaluate this value to print it out into the F# Interactive console
singleResult

更新實體

若要更新實體,請使用 TableUpdateMode.Replace 作業從資料表服務擷取實體,修改實體物件,然後將變更儲存回資料表服務。 這麼做會讓系統完全取代伺服器上的實體,但如果伺服器上的實體自擷取後已有所改變,作業將會失敗。 系統會讓作業失敗是為了防止應用程式意外覆寫來自其他來源的變更。

singleResult.PhoneNumber <- "425-555-0103"
try
    table.UpdateEntity (singleResult, ETag "", TableUpdateMode.Replace) |> ignore
    printfn "Update succeeded"
with
| :? RequestFailedException as e ->
    printfn $"Update failed: {e.Status} - {e.ErrorCode}"

更新插入實體

有時候,您不知道某個實體是否存在於資料表中。 如果存在,您就不再需要實體中儲存的目前值。 您可以使用 UpsertEntity 方法來建立實體,如果實體存在則加以取代,而不論其狀態為何。

singleResult.PhoneNumber <- "425-555-0104"
table.UpsertEntity (singleResult, TableUpdateMode.Replace)

查詢實體屬性的子集

資料表查詢可以只擷取實體的一些屬性,而非擷取其所有屬性。 這項稱為投影的技術可提升查詢效能 (尤其是對大型實體而言)。 在這裡,您會使用 Query<T>Select 來只傳回電子郵件地址。 在本機儲存體模擬器上並不支援投影,因此此程式碼只有在資料表服務上使用帳戶時才會執行。

query {
    for customer in table.Query<Customer> () do
    select customer.Email
}

非同步地擷取頁面中的實體

如果您要讀取大量實體,且您想要在擷取實體時處理實體,但不想等待實體全部傳回,則可以使用分割查詢。 在這裡,您會使用非同步工作流程以在頁面中傳回結果,如此一來,在您等候大量結果集傳回時,系統便不會阻止作業執行。

let pagesResults = table.Query<Customer> ()

for page in pagesResults.AsPages () do
    printfn "This is a new page!"
    for customer in page.Values do
        printfn $"customer: {customer.RowKey} {customer.PartitionKey}"

刪除實體

您可以刪除已擷取的實體。 和更新實體時一樣,如果實體自擷取後已有所變更,此作業便會失敗。

table.DeleteEntity ("Smith", "Ben")

刪除資料表

您可以從儲存體帳戶中刪除資料表。 已刪除的資料表在刪除後的一定時間內,將無法重新建立。

table.Delete ()

另請參閱