Introdução ao Armazenamento de Tabelas do Azure e à API de Tabela do Azure Cosmos DB usando F#

O Armazenamento de Tabelas do Azure é um serviço que armazena dados NoSQL estruturados na nuvem. O armazenamento de Tabelas é um repositório de chaves/atributos com um design sem esquema. Como o armazenamento de Tabelas não tem um esquema, é fácil adaptar seus dados à medida que as necessidades de seu aplicativo evoluem. O acesso aos dados é rápido e econômico para todos os tipos de aplicativos. O armazenamento de tabela normalmente tem um custo significativamente mais baixo do que o SQL tradicional para volumes de dados semelhantes.

Você pode usar o armazenamento de tabela para armazenar conjuntos de dados flexíveis, como dados de usuário para aplicativos web, catálogos de endereços, informações sobre dispositivos e qualquer outro tipo de metadados que o serviço requeira. Você pode armazenar qualquer número de entidades em uma tabela e uma conta de armazenamento pode conter um número ilimitado de tabelas, até o limite de capacidade da conta de armazenamento.

O Azure Cosmos DB fornece a API de Tabela para aplicativos que são escritos para o Armazenamento de Tabelas do Azure e que precisam de recursos especiais, como:

  • Distribuição global turnkey.
  • Taxa de transferência dedicada em todo o mundo.
  • Latências de dígito único em milissegundos no percentil 99.
  • Alta disponibilidade garantia.
  • Indexação automática secundária.

Esses aplicativos escritos para o Armazenamento de Tabelas do Azure podem migrar para o Azure Cosmos DB usando a API de Tabelas, sem alterações de código e tirando proveito dos recursos especiais. A API de Tabela tem SDKs de cliente disponíveis para .NET, Java, Python e Node.js.

Para obter mais informações, confira a Introdução à API de Tabela do Azure Cosmos DB.

Sobre este tutorial

Este tutorial mostra como escrever código F# para realizar algumas tarefas comuns usando o Armazenamento de Tabelas do Azure ou a API de Tabela do Azure Cosmos DB, incluindo criação e exclusão de tabela, bem como inserção, atualização, exclusão e consulta de dados da tabela.

Pré-requisitos

Para usar este guia, primeiro você deve criar uma conta de armazenamento do Azure ou uma conta do Azure Cosmos DB.

Criar um script F# e iniciar o F# Interativo

Os exemplos deste artigo podem ser usados em um aplicativo F# ou em um script F#. Para criar um script F#, crie um arquivo com a extensão .fsx, por exemplo, tables.fsx, no ambiente de desenvolvimento F#.

Como executar scripts

O F# Interativo, dotnet fsi, pode ser iniciado de maneira interativa ou na linha de comando para executar um script. A sintaxe da linha de comando é

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

Adicionar pacotes em um script

Em seguida, use #rnuget:package name para instalar o pacote Azure.Data.Tables e os namespaces open. Como

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

Adicionar declarações do namespace

Adicione as seguintes instruções open à parte superior do arquivo tables.fsx:

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

Obter a cadeia de conexão de Armazenamento do Azure

Se você estiver se conectando ao serviço Tabela de Armazenamento do Azure, precisará da cadeia de conexão para este tutorial. Você pode copiar a cadeia de conexão do portal do Azure. Para saber mais sobre cadeias de conexão, confira Configurar cadeias de conexão de armazenamento.

Obter a cadeia de conexão do Azure Cosmos DB

Se você estiver se conectando ao Azure Cosmos DB, precisará da cadeia de conexão para este tutorial. Você pode copiar a cadeia de conexão do portal do Azure. No portal do Azure, em sua conta do Cosmos DB, acesse Configurações>Cadeia de Conexão e selecione o botão Copiar para copiar a cadeia de conexão primária.

Para o tutorial, insira a cadeia de conexão no script, como neste exemplo:

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

Criar o cliente do serviço Tabela

A classe TableServiceClient permite que você recupere as tabelas e entidades no Armazenamento de Tabelas. Veja uma maneira de criar o cliente de serviço:

let tableClient = TableServiceClient storageConnString

Agora você está pronto para escrever um código que lê e grava dados no Armazenamento de Tabelas.

Criar uma tabela

Este exemplo mostra como criar uma tabela se ela ainda não existe:

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

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

Adicionar uma entidade a uma tabela

Uma entidade precisa ter um tipo que implemente ITableEntity. Você pode estender ITableEntity da maneira que quiser, mas o tipo deve ter um construtor sem parâmetros. Somente propriedades que têm ambos get e set são armazenadas em sua Tabela do Azure.

A chave de partição e a chave de linha da entidade identificam exclusivamente a entidade na tabela. As entidades com a mesma chave de partição podem ser consultadas mais rápido do que aquelas com chaves de partição diferentes, mas usar chaves de partição diferentes permite uma escalabilidade maior de operações paralelas.

Aqui está um exemplo de Customer que usa lastName como chave de partição e firstName como chave de linha.

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

Agora, adicione Customer à tabela. Para isso, podemos usar o método AddEntity().

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

Inserir um lote de entidades

Você pode inserir um lote de entidades em uma tabela em uma única operação de gravação. As operações em lote permitem combinar operações em uma única execução, mas elas têm algumas restrições:

  • Você pode executar atualizações, exclusões e inserções na mesma operação em lote.
  • Uma operação em lote pode incluir até 100 entidades.
  • Todas as entidades em uma operação em lote devem ter a mesma chave de partição.
  • Embora seja possível executar uma consulta em uma operação em lote, ela deve ser a única operação no lote.

Eis aqui um código que combina duas inserções em uma operação em lote:

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

Recuperar todas as entidades em uma partição

Para consultar uma tabela para todas as entidades em uma partição, use um objeto Query<T>. Aqui, você filtra entidades em que "Smith" é a chave de partição.

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

Recuperar um intervalo de entidades em uma partição

Se não desejar consultar todas as entidades em uma partição, você poderá especificar um intervalo combinando o filtro de chave de partição com um filtro de chave de linha. Aqui, você usa dois filtros para obter todas as entidades da partição “Smith”, onde a chave da linha (nome) começa com uma letra anterior a “M” no alfabeto.

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

Recuperar uma única entidade

Para recuperar uma única entidade específica, use GetEntityAsync para especificar o cliente "Ben Smith". Em vez de uma coleção, você obtém Customer. Especificar chaves de partição e de linha em uma consulta é a maneira mais rápida de recuperar uma única entidade do serviço Tabela.

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

Agora, você imprime os resultados:

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

Atualizar uma entidade

Para atualizar uma entidade, recupere-a do serviço Tabela, modifique o objeto de entidade e, em seguida, salve as alterações novamente no serviço Tabela, usando uma operação TableUpdateMode.Replace. Isso faz com que a entidade seja totalmente substituída no servidor, a menos que a entidade no servidor tenha sido alterada desde que foi recuperada, caso em que a operação falhará. Essa falha é para impedir o aplicativo de substituir inadvertidamente as alterações de outras fontes.

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}"

Executar upsert de uma entidade

Às vezes, você não sabe se uma entidade está na tabela. Se esse for o caso, os valores atuais armazenados nela não serão mais necessários. Você pode usar o método UpsertEntity para criar a entidade ou substituí-la, se ela existir, independentemente do seu estado.

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

consultar um subconjunto de propriedades da entidade

Uma consulta de tabela pode recuperar apenas algumas propriedades de uma entidade e não todas elas. Essa técnica, chamada de projeção, pode melhorar o desempenho da consulta, principalmente para entidades grandes. Aqui, você retorna apenas endereços de email usando Query<T> e Select. A projeção não é compatível com o emulador de armazenamento local. Portanto, esse código é executado somente ao usar uma conta no serviço Tabela.

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

Recuperar entidades nas páginas de forma assíncrona

Se estiver lendo muitas entidades e quiser processá-las quando forem recuperadas, em vez de esperar que todas sejam retornadas, você pode usar uma consulta segmentada. Aqui, você retorna resultados nas páginas usando um fluxo de trabalho assíncrono para que a execução não fique bloqueada enquanto espera o retorno de um grande conjunto de resultados.

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}"

Excluir uma entidade

Você poderá excluir uma entidade depois de recuperá-la. Assim como na atualização de uma entidade, isso falhará se a entidade tiver sido alterada após a recuperação.

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

Excluir uma tabela

Você pode excluir uma tabela de uma conta de armazenamento. Uma tabela excluída não estará disponível para ser recriada por algum período após a exclusão.

table.Delete ()

Confira também