Executando verificação de segurança...
0

Boas práticas de armazenamento de comandos Dapper .NET

Ao utilizar o Dapper em uma aplicação .NET, é importante organizar os comandos SQL de forma que eles sejam reutilizáveis, fáceis de manter e seguros.

  1. Armazenar SQL em Arquivos Separados:
    Armazene os comandos SQL em arquivos .sql dentro de uma pasta, como SQL/Queries. Use File.ReadAllText() para carregar os comandos.
    Estrutura de pastas:

    /SQL
      /Product
        GetAllProducts.sql
        GetProductById.sql
        InsertProduct.sql
        UpdateProduct.sql
        DeleteProduct.sql
    

    Exemplo de leitura:

     ```C#
     string sql = File.ReadAllText("SQL/Product/GetAllProducts.sql").Replace("\n", " ").Replace("\r", "").Trim();//(removendo espaços de identação)
     ```
    

    Vantagens:
    • Comandos SQL ficam separados do código C#, facilitando a leitura e a organização.
    • Ideal para comandos SQL longos e complexos.

  2. Usar Recursos como Embedded Resources:
    Armazene os comandos SQL em arquivos .sql e inclua-os como Recursos Incorporados no projeto. Carregue os arquivos com Assembly.GetManifestResourceStream.

    Exemplo de uso
    • Configure o arquivo .sql como Embedded Resource nas propriedades do arquivo.
    • Carregue o arquivo no código:

     ```C#
     string sql;
     var assembly = Assembly.GetExecutingAssembly();
     using (var stream = assembly.GetManifestResourceStream("YourNamespace.SQL.Product.GetAllProducts.sql"))
     using (var reader = new StreamReader(stream))
     {
         sql = reader.ReadToEnd().Replace("\n", " ").Replace("\r", "").Trim();//(removendo espaços de identação)
     }
     ```
    
     Vantagens:
         • SQL fica dentro do binário, evitando alterações acidentais no ambiente de produção.
         • Segurança adicional para proteger o código SQL.
    

Independente da forma de armazenamento, sempre use parâmetros nas consultas para evitar injeção de SQL.

Exemplo de uso seguro:

```C#
string sql = "SELECT * FROM Products WHERE Name = @Name";
var products = await connection.QueryAsync<Product>(sql, new { Name = "Example" });
``` 

Comparação em performance

  1. Arquivos Externos:
    As queries são armazenadas em arquivos .sql no sistema de arquivos e carregadas em tempo de execução.

    Vantagens de Performance
    • Tamanho do executável menor: O binário final não inclui as queries diretamente.
    • Separação de responsabilidades: Facilita a manutenção e atualização das queries sem recompilar o código.

    Desvantagens de performance
    • Leitura de arquivos: Cada vez que um arquivo é acessado, há uma operação de I/O, que é mais lenta do que acessar strings em memória.
    • Mitigação: Use cache em memória para armazenar queries lidas previamente.
    • Risco de falhas: Se o arquivo for movido ou excluído, a aplicação pode falhar.

    Cenário de Uso
    • Adequado para projetos grandes com queries longas ou complexas que precisam ser atualizadas com frequência sem alterar o código.

  2. Recursos Incorporados
    As queries são armazenadas em arquivos .sql e configuradas como Embedded Resources no projeto, sendo incorporadas ao binário no momento da compilação.

    Vantagens de Performance
    • Sem I/O no disco: Os recursos incorporados são acessados diretamente da memória do binário, eliminando operações de disco.
    • Tamanho fixo do executável: As queries são incorporadas ao executável, evitando dependências externas.
    • Organização: Manter queries separadas em arquivos melhora a legibilidade e manutenção.

    Desvantagens de Performance
    • Maior consumo de memória inicial: Os recursos incorporados aumentam o tamanho do binário e são carregados na memória junto com a aplicação.
    • Menor flexibilidade: Atualizar as queries exige recompilar o projeto.

Cenário de Uso

Ótimo para projetos onde as queries raramente mudam e há necessidade de um executável autossuficiente.

Comparação de Performance

CritérioArquivo ExternoRecurso Incorporado
Velocidade de AcessoMédia (I/O de disco)Alta (em memória)
Tamanho do BinárioMenorMaior
FlexibilidadeAltaMédia
Facilidade de AtualizaçãoAltaBaixa

Conclusão

  1. Melhor para Manutenção e Flexibilidade:
    • Arquivos Externos (permitem alterações sem recompilar a aplicação).
  2. Recomendação Geral:
    • Para projetos grandes e dinâmicos, use Arquivos Externos com cache em memória para balancear flexibilidade e desempenho.

Observações gerais
Alguns projetos são usados a string command diretamente como string estática no código fonte não caracterizando uma boa prática por conta de alguns fatores que podemos listar:
• Se o texto da query será carregado na memória com identação, serão armazenados e enviados como parte da consulta deixando o tamanho do binário maior.
• Implica na dificuldade de versionamento especificadamente do comando.
• Comando diretamente exposto no código pode não ter uma boa legibilidade, pois não separa a responsabilidade corretamente.
• Pode ser um ponto de atenção na questão de segurança, isso deve ser avaliado cada código em particular para identificar possíveis "furos".

Carregando publicação patrocinada...
3

O primeiro vídeo do meu canal se chamará "A Péssima Prática de Seguir Boas Práticas".

Primeiro porque as pessoas fazem muito sem contexto e sem considerar todas as questões. E eu mesmo não considerarei todas aqui. A maioria das tais "boas práticas" de boas só tem o nome, e vou explicar isso melhor, conforme já fiz diversas vezes em palestras.

Não faz muito sentido criar 3 strings desnecessárias para a operação, poderia ler o stream e já filtrar o que vem. Dá um pouco mais de trabalho porque falta algo pronto que faça isso, mas faz sentido quando se fala em performence e consumo de memória. Pode ser que ela não importe, aí é um ponto a desconsiderar.

Consumo de memória inicial mais alto não sei se deveria ser considerado desvantagem, até porque eu precisaria medir para dar um parecer correto e analisar melhor se isso tem algum impacto, que pode até ser positivo.

De qualquer forma o acesso ao arquivo deveria ser considerado baixo em performance porque é centenas de vezes mais lento que o acesso em memória.

O problema do arquivo externo é a segurança bem mais fragilizada. Não que não dê para burlar no incorporado, e em muitos casos não importa já que o acesso será restrito mesmo, mas é bom falar sobre isso para certos contextos.

Não importa olhar para o tamanho do binário, o tamanho da solução é que é relevante, e em essência dá na mesma.

A flexibilidade é algo que pode ser vista de maneiras diferenets, então sem um critério bem definido essa ideia fica vaga e nem podemos avaliar/comparar.

Tenho medo dee queries que precisam ser atualizadas com tanta facilidade assim.

Usar apenas strings simples organizadas para forma que for mais conveniente e correta pode ser uma solução ótima para muitos casos. Inclusive pode ser uma forma de apenas recompilar essa parte e não toda a aplicação (acho que dá para fazer isso com o recurso no executável também). Dificuldade de versionamento pode ser a solução para versionar melhor, muitas vezes a facilidade implica em bagunça. Não é pior em segurança e a legibilidade só depende de como a pessoa programou. Pode ser mais legível dependendo do objetivo. Eu diria que a maioria dos projetos será mais legível assim, nem sempre esconder algo é uma boa opção. E pode facilitar a manutenção, tudo depende.

A recomendação geral é sempre entender toda a computação, o contexto e decidir o que é melhor para o caso específico. Em muitos casos tanto faz e o que for mais fácil de fazer é melhor.

Se tem "boas práticas" ruins recomendadas por alguns dos profisssionais mais repeitados do mercado, até porque pode não considerar o contexto, imagine o quanto tem pela internet toda sem controle algum.

S2


Farei algo que muitos pedem para aprender a programar corretamente, gratuitamente (não vendo nada, é retribuição na minha aposentadoria) (links aqui no perfil também).