Usando a biblioteca cliente de banco de dados elástico com o Dapper

Aplica-se a:Banco de Dados SQL do Azure

Este documento é para desenvolvedores que dependem do Dapper para criar aplicativos, mas também querem adotar ferramentas de banco de dados elástico para criar aplicativos que implementam fragmentação para expandir sua camada de dados. Este documento ilustra as alterações nos aplicativos baseados no Dapper que são necessárias para integrar com ferramentas de banco de dados elástico. Nosso foco é compor o gerenciamento de estilhaços de banco de dados elástico e o roteamento dependente de dados com o Dapper.

Código de exemplo: Ferramentas de banco de dados elástico para integração do Banco de Dados SQL do Azure - Dapper.

É fácil integrar Dapper e DapperExtensions com a biblioteca de cliente de banco de dados elástico do Banco de Dados SQL do Azure. Seus aplicativos podem usar o roteamento dependente de dados alterando a criação e a abertura de novos objetos SqlConnection para usar a chamada OpenConnectionForKey da biblioteca do cliente. Isso limita as alterações em seu aplicativo apenas onde novas conexões são criadas e abertas.

Visão geral do Dapper

Dapper é um mapeador objeto-relacional. Ele mapeia objetos .NET do seu aplicativo para um banco de dados relacional (e vice-versa). A primeira parte do código de exemplo ilustra como você pode integrar a biblioteca cliente de banco de dados elástico com aplicativos baseados em Dapper. A segunda parte do código de exemplo ilustra como integrar ao usar Dapper e DapperExtensions.

A funcionalidade de mapeador no Dapper fornece métodos de extensão em conexões de banco de dados que simplificam o envio de instruções T-SQL para execução ou consulta ao banco de dados. Por exemplo, o Dapper facilita o mapeamento entre seus objetos .NET e os parâmetros de instruções SQL para chamadas Execute ou o consumo dos resultados de suas consultas SQL em objetos .NET usando chamadas Query do Dapper.

Ao usar DapperExtensions, você não precisa mais fornecer as instruções SQL. Métodos de extensões como GetList ou Insert sobre a conexão de banco de dados criam as instruções SQL nos bastidores.

Outro benefício do Dapper e também do DapperExtensions é que o aplicativo controla a criação da conexão do banco de dados. Isso ajuda a interagir com a biblioteca cliente de banco de dados elástico que intermedia conexões de banco de dados com base no mapeamento de shardlets para bancos de dados.

Para obter os assemblies do Dapper, consulte Dapper dot net. Para as extensões Dapper, consulte DapperExtensions.

Uma rápida olhada na biblioteca de cliente de banco de dados elástico

Com a biblioteca cliente de banco de dados elástico, você define partições de seus dados de aplicativo chamadas shardlets, mapeia-as para bancos de dados e as identifica por meio de chaves de fragmentação. Você pode ter quantos bancos de dados precisar e distribuir seus shardlets entre esses bancos de dados. O mapeamento de valores de chave de fragmentação para os bancos de dados é armazenado por um mapa de fragmentos fornecido pelas APIs da biblioteca. Esse recurso é chamado de gerenciamento de mapa de estilhaços. O mapa de estilhaços também serve como o agente de conexões de banco de dados para solicitações que carregam uma chave de fragmentação. Esse recurso é conhecido como roteamento dependente de dados.

Shard maps and data-dependent routing

O gerenciador de mapas de fragmentos protege os usuários contra exibições inconsistentes em dados de shardlet que podem ocorrer quando operações simultâneas de gerenciamento de shardlet estão acontecendo nos bancos de dados. Para fazer isso, os mapas de estilhaços intermediam as conexões de banco de dados para um aplicativo criado com a biblioteca. Quando as operações de gerenciamento de estilhaços podem afetar o shardlet, isso permite que a funcionalidade de mapa de estilhaços mate automaticamente uma conexão de banco de dados.

Em vez de usar a maneira tradicional de criar conexões para o Dapper, você precisa usar o método OpenConnectionForKey. Isso garante que toda a validação ocorra e que as conexões sejam gerenciadas corretamente quando quaisquer dados forem movidos entre fragmentos.

Requisitos para integração com o Dapper

Ao trabalhar com a biblioteca cliente de banco de dados elástico e as APIs do Dapper, você deseja manter as seguintes propriedades:

  • Dimensionamento: queremos adicionar ou remover bancos de dados da camada de dados do aplicativo fragmentado conforme necessário para as demandas de capacidade do aplicativo.
  • Consistência: Como o aplicativo é dimensionado usando fragmentação, você precisa executar o roteamento dependente de dados. Queremos usar os recursos de roteamento dependentes de dados da biblioteca para fazer isso. Em particular, você deseja manter as garantias de validação e consistência fornecidas por conexões que são intermediadas através do gerenciador de mapa de estilhaços para evitar corrupção ou resultados de consulta errados. Isso garante que as conexões com um determinado shardlet sejam rejeitadas ou interrompidas se (por exemplo) o shardlet for atualmente movido para um fragmento diferente usando APIs de Split/Merge.
  • Mapeamento de objetos: Queremos manter a conveniência dos mapeamentos fornecidos pelo Dapper para traduzir entre classes no aplicativo e as estruturas de banco de dados subjacentes.

A seção a seguir fornece orientação para esses requisitos para aplicativos baseados em Dapper e DapperExtensions.

Orientação técnica

Roteamento dependente de dados com o Dapper

Com o Dapper, o aplicativo normalmente é responsável por criar e abrir as conexões com o banco de dados subjacente. Dado um tipo T pelo aplicativo, o Dapper retorna resultados de consulta como coleções .NET do tipo T. O Dapper executa o mapeamento das linhas de resultados do T-SQL para os objetos do tipo T. Da mesma forma, o Dapper mapeia objetos .NET em valores ou parâmetros SQL para instruções DML (linguagem de manipulação de dados). O Dapper oferece essa funcionalidade por meio de métodos de extensão no objeto SqlConnection regular das bibliotecas ADO .NET SQL Client. A conexão SQL retornada pelas APIs do Elastic Scale para DDR também são objetos SqlConnection regulares. Isso nos permite usar diretamente as extensões Dapper sobre o tipo retornado pela API DDR da biblioteca cliente, pois também é uma conexão simples do SQL Client.

Essas observações tornam simples o uso de conexões intermediadas pela biblioteca de cliente de banco de dados elástico para o Dapper.

Este exemplo de código (do exemplo que acompanha) ilustra a abordagem em que a chave de fragmentação é fornecida pelo aplicativo à biblioteca para intermediar a conexão com o fragmento correto.

    using (SqlConnection sqlconn = shardingLayer.ShardMap.OpenConnectionForKey(
                     key: tenantId1,
                     connectionString: connStrBldr.ConnectionString,
                     options: ConnectionOptions.Validate))
    {
        var blog = new Blog { Name = name };
        sqlconn.Execute(@"
                      INSERT INTO
                            Blog (Name)
                            VALUES (@name)", new { name = blog.Name }
                        );
    }

A chamada para a API OpenConnectionForKey substitui a criação e abertura padrão de uma conexão de cliente SQL. A chamada OpenConnectionForKey usa os argumentos necessários para o roteamento dependente de dados:

  • O mapa de estilhaços para acessar as interfaces de roteamento dependentes de dados
  • A chave de fragmentação para identificar o fragmento
  • As credenciais (nome de usuário e senha) para se conectar ao fragmento

O objeto de mapa de estilhaços cria uma conexão com o fragmento que contém o fragmento para a chave de fragmentação fornecida. As APIs do cliente de banco de dados elástico também marcam a conexão para implementar suas garantias de consistência. Como a chamada para OpenConnectionForKey retorna um objeto de conexão SQL Client regular, a chamada subsequente para o método de extensão Execute do Dapper segue a prática padrão do Dapper.

As consultas funcionam da mesma maneira - você primeiro abre a conexão usando OpenConnectionForKey da API do cliente. Em seguida, use os métodos de extensão Dapper regulares para mapear os resultados da consulta SQL em objetos .NET:

    using (SqlConnection sqlconn = shardingLayer.ShardMap.OpenConnectionForKey(
                    key: tenantId1,
                    connectionString: connStrBldr.ConnectionString,
                    options: ConnectionOptions.Validate ))
    {
           // Display all Blogs for tenant 1
           IEnumerable<Blog> result = sqlconn.Query<Blog>(@"
                                SELECT *
                                FROM Blog
                                ORDER BY Name");

           Console.WriteLine("All blogs for tenant id {0}:", tenantId1);
           foreach (var item in result)
           {
                Console.WriteLine(item.Name);
            }
    }

Observe que o bloco de uso com o escopo de conexão DDR escopos todas as operações de banco de dados dentro do bloco para o fragmento onde tenantId1 é mantido. A consulta retorna apenas blogs armazenados no fragmento atual, mas não os armazenados em qualquer outro fragmento.

Roteamento dependente de dados com Dapper e DapperExtensions

O Dapper vem com um ecossistema de extensões adicionais que podem fornecer mais conveniência e abstração do banco de dados ao desenvolver aplicativos de banco de dados. DapperExtensions é um exemplo.

Usar DapperExtensions em seu aplicativo não altera como as conexões de banco de dados são criadas e gerenciadas. Ainda é responsabilidade do aplicativo abrir conexões, e objetos de conexão regulares do SQL Client são esperados pelos métodos de extensão. Podemos confiar no OpenConnectionForKey como descrito acima. Como mostram os exemplos de código a seguir, a única alteração é que você não precisa mais escrever as instruções T-SQL:

    using (SqlConnection sqlconn = shardingLayer.ShardMap.OpenConnectionForKey(
                    key: tenantId2,
                    connectionString: connStrBldr.ConnectionString,
                    options: ConnectionOptions.Validate))
    {
           var blog = new Blog { Name = name2 };
           sqlconn.Insert(blog);
    }

E aqui está o exemplo de código para a consulta:

    using (SqlConnection sqlconn = shardingLayer.ShardMap.OpenConnectionForKey(
                    key: tenantId2,
                    connectionString: connStrBldr.ConnectionString,
                    options: ConnectionOptions.Validate))
    {
           // Display all Blogs for tenant 2
           IEnumerable<Blog> result = sqlconn.GetList<Blog>();
           Console.WriteLine("All blogs for tenant id {0}:", tenantId2);
           foreach (var item in result)
           {
               Console.WriteLine(item.Name);
           }
    }

Tratamento de falhas transitórias

A equipe de Padrões e Práticas da Microsoft publicou o Bloco de Aplicativo de Tratamento de Falhas Transitórias para ajudar os desenvolvedores de aplicativos a mitigar condições comuns de falhas transitórias encontradas durante a execução na nuvem. Para obter mais informações, consulte Perseverance, Secret of All Triumphs: Using the Transient Fault Handling Application Block.

O exemplo de código depende da biblioteca de falhas transitórias para proteger contra falhas transitórias.

    SqlDatabaseUtils.SqlRetryPolicy.ExecuteAction(() =>
    {
       using (SqlConnection sqlconn =
          shardingLayer.ShardMap.OpenConnectionForKey(tenantId2, connStrBldr.ConnectionString, ConnectionOptions.Validate))
          {
              var blog = new Blog { Name = name2 };
              sqlconn.Insert(blog);
          }
    });

SqlDatabaseUtils.SqlRetryPolicy no código acima é definido como um SqlDatabaseTransientErrorDetectionStrategy com uma contagem de tentativas de 10 e 5 segundos de tempo de espera entre as tentativas. Se você estiver usando transações, certifique-se de que seu escopo de repetição volte ao início da transação no caso de uma falha transitória.

Limitações

As abordagens delineadas neste documento implicam algumas limitações:

  • O código de exemplo para este documento não demonstra como gerenciar o esquema entre fragmentos.
  • Dada uma solicitação, assumimos que todo o seu processamento de banco de dados está contido em um único fragmento, conforme identificado pela chave de fragmentação fornecida pela solicitação. No entanto, este pressuposto nem sempre se mantém, por exemplo, quando não é possível disponibilizar uma chave de fragmentação. Para resolver isso, a biblioteca de cliente de banco de dados elástico inclui a classe MultiShardQuery. A classe implementa uma abstração de conexão para consultar vários fragmentos. Usar o MultiShardQuery em combinação com o Dapper está além do escopo deste documento.

Conclusão

Os aplicativos que usam Dapper e DapperExtensions podem se beneficiar facilmente das ferramentas de banco de dados elástico para o Banco de Dados SQL do Azure. Por meio das etapas descritas neste documento, esses aplicativos podem usar o recurso da ferramenta para roteamento dependente de dados alterando a criação e a abertura de novos objetos SqlConnection para usar a chamada OpenConnectionForKey da biblioteca cliente de banco de dados elástico. Isso limita as alterações de aplicativo necessárias para os locais onde novas conexões são criadas e abertas.

Recursos adicionais

Ainda não está usando ferramentas de banco de dados elástico? Consulte o nosso Guia de Introdução. Para dúvidas, entre em contato conosco na página de perguntas e respostas da Microsoft para o Banco de dados SQL e para solicitações de recursos, adicione novas ideias ou vote em ideias existentes no fórum de comentários do Banco de dados SQL.