O SQL embutido ainda é classificado como prática ruim agora que temos Micro ORMs?

26

Esta é uma pergunta aberta, mas eu queria algumas opiniões, pois cresci em um mundo onde os scripts SQL embutidos eram a norma, e todos nos conscientizamos dos problemas baseados em injeção SQL e da fragilidade do sql quando fazendo manipulações de cordas em todo o lugar.

Chegou então o início do ORM, onde você estava explicando a consulta ao ORM e permitindo que ele gerasse seu próprio SQL, que em muitos casos não era o ideal, mas era seguro e fácil. Outra coisa boa sobre os ORMs ou as camadas de abstração de banco de dados foi que o SQL foi gerado com o mecanismo de banco de dados em mente, para que eu pudesse usar o Hibernate / Nhibernate com MSSQL, MYSQL e meu código nunca mudou, era apenas um detalhe de configuração.

Agora, avançando rapidamente para o dia atual, em que os micro ORMs parecem estar conquistando mais desenvolvedores, fiquei pensando por que aparentemente fizemos uma inversão de marcha em todo o assunto sql em linha.

Devo admitir que gosto da ideia de não haver arquivos de configuração do ORM e poder escrever minha consulta de maneira mais otimizada, mas parece que estou me abrindo de volta para as vulnerabilidades antigas, como a injeção de SQL, e também estou me comprometendo a um mecanismo de banco de dados, portanto, se eu quiser que meu software ofereça suporte a vários mecanismos de banco de dados, precisarei fazer mais algumas invasões de strings, que parecem começar a tornar o código ilegível e mais frágil. (Pouco antes de alguém mencionar, eu sei que você pode usar argumentos baseados em parâmetros com a maioria das micro orms, que oferece proteção na maioria dos casos contra injeção de sql)

Então, quais são as opiniões das pessoas sobre esse tipo de coisa? Estou usando o Dapper como meu Micro ORM nesta instância e o NHibernate como meu ORM comum nesse cenário, porém a maioria em cada campo é bastante semelhante.

O que chamo de sql embutidosão seqüências de caracteres SQL no código-fonte. Costumava haver debates sobre o design de strings SQL no código-fonte, prejudicando a intenção fundamental da lógica, e é por isso que as consultas no estilo linq com estaticamente se tornaram tão populares ainda em apenas 1 idioma, mas digamos C # e Sql em uma página que você possui. 2 idiomas misturados no seu código-fonte bruto agora. Apenas para esclarecer, a injeção de SQL é apenas um dos problemas conhecidos com o uso de seqüências de caracteres sql. Já mencionei que você pode impedir que isso aconteça com consultas baseadas em parâmetros, no entanto, destaco outros problemas com a consulta de SQL no seu código-fonte, como a falta de abstração do DB Vendor e a perda de qualquer nível de captura de erros em tempo de compilação em consultas baseadas em strings, todos esses problemas foram resolvidos com o surgimento dos ORMs com sua funcionalidade de consulta de nível superior,

Portanto, estou menos focado nas questões individuais destacadas e, quanto mais amplo, agora é mais aceitável ter seqüências SQL diretamente no seu código-fonte novamente, pois a maioria dos Micro ORMs usa esse mecanismo.

Aqui está uma pergunta semelhante que tem alguns pontos de vista diferentes, embora seja mais sobre o sql inline sem o contexto de micro orm:

/programming/5303746/is-inline-sql-hard-coding

Grofit
fonte
1
Você acha que poderia reformular a pergunta de tal maneira que ela não solicite uma opinião? A pesquisa de opiniões não se encaixa bem no formato de perguntas e respostas do Stack Exchange.
Você sempre pode abstrair suas consultas "Micro ORM" em uma classe separada, onde, quando necessário, você troca as consultas que estão sendo executadas à medida que altera seu DBMS.
CodeCaster
não ouviu o termo "Micro ORM". você quer dizer ORMs que não tentam assumir completamente o SQL ou é algo diferente?
Javier
deixa pra lá, depois de pesquisar um pouco, parece uma coisa .net.
Javier
1
@GrandmasterB: Explique o porquê em uma resposta. Eu praticamente evitei esse problema na minha resposta, pois acredito que é uma questão de trocas.
Robert Harvey

Respostas:

31

O que você está descrevendo como "SQL embutido" deve realmente ser chamado de "concatenação de strings sem parametrização" e não é necessário fazer isso para usar um Micro ORM com segurança.

Considere este exemplo Dapper:

string sql = "SELECT * from user_profile WHERE FirstName LIKE @name;";
var result = connection.Query<Profile>(sql, new {name = "%"+name+"%"});

É totalmente parametrizado, mesmo que a concatenação de strings esteja ocorrendo. Veja o sinal @?

Ou este exemplo:

var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", 
          new { Age = (int?)null, Id = guid });

que é aproximadamente equivalente ao seguinte código ADO.NET:

List<Dog> dog = new List<Dog>();
using(var cmd = connection.CreateCommand()) {
    cmd.CommandText = "select Age = @Age, Id = @Id";
    cmd.Parameters.AddWithValue("Age", DBNull.Value);
    cmd.Parameters.AddWithValue("Id", guid);
    using(var reader = cmd.ExecuteReader()) {
        while(reader.Read()) {
            int age = reader.ReadInt32("Age");
            int id = reader.ReadInt32("Id");
            dog.Add(new Dog { Age = age, Id = id });
        }
    }
}

Se você precisar de mais flexibilidade do que isso, o Dapper fornece modelos SQL e uma AddDynamicParms()função. Toda a injeção de SQL segura.

Então, por que usar strings SQL em primeiro lugar?

Bem, pelos mesmos motivos, você usaria SQL personalizado em qualquer outro ORM. Talvez o ORM seja um SQL subótimo que gera código e você precise otimizá-lo. Talvez você queira fazer algo que é difícil de fazer no ORM nativamente, como UNIONs. Ou talvez você queira simplesmente evitar a complexidade de gerar todas essas classes de proxy.

Se você realmente não deseja escrever uma string SQL para cada método CRUD no Dapper (quem faz?), Você pode usar esta biblioteca:

https://github.com/ericdc1/Dapper.SimpleCRUD/

Isso proporcionará a você CRUD extremamente simples e direto, enquanto oferece a flexibilidade de instruções SQL escritas à mão. Lembre-se, o exemplo do ADO.NET acima foi o que todo mundo fazia antes do ORM; Dapper é apenas um verniz fino sobre isso.

Robert Harvey
fonte
Bons exemplos, eu já mencionei que você pode contornar a injeção de SQL por meio de parâmetros, pois essa é apenas uma parte da questão maior. Também adicionamos uma edição esclarecendo o que quero dizer quando uso o termo sql inline .
Grofit
Eu adicionei alguns detalhes à minha resposta.
Robert Harvey
2
+1 para obter informações sobre o SimpleCRUD não sabia que isso existia.
Grofit 17/10
Em Java, você encontrará Mybatis, que é mais que Hibernate ou EclipseLink e. Seu caminho a seguir é por frases predefinidas em XML (em vez de codificar no código). Ele também adiciona alguns recursos interessantes como pré-condições para aprimorar o SQL final. Recentemente, usamos uma web de APIs com simultaneidade bastante alta e um negócio não complexo e funcionou muito bem.
Laiv 27/05
2

Eu amo sql , e não aguentava vê-lo dividido em literais de string, então escrevi uma pequena extensão do VS para permitir que você trabalhe com arquivos sql reais em projetos c #. A edição do sql em seu próprio arquivo fornece informações inteligentes para colunas e tabelas, validação de sintaxe, execução de teste, planos de execução e o restante. Quando você salva o arquivo, minha extensão gera classes de wrapper c #, para que você nunca escreva uma linha de código de conexão, código de comando ou parâmetro ou código do leitor. Suas consultas são todas parametrizadas porque não há outra maneira, e você gerou repositórios e POCOs para teste de unidade, com intellisense para seus parâmetros de entrada e seus resultados.

E eu joguei facas de bife gratuitas ... Quando um especialista precisa vir e refazer o sql do seu desenvolvedor, ele está olhando para um arquivo sql real e não precisa tocar em nenhum c #. Quando ela volta e arruma o banco de dados, excluindo algumas colunas, as referências às colunas ausentes saltam diretamente como erros de compilação no c #. O banco de dados se torna como outro projeto em sua solução que você pode invadir, sua interface pode ser descoberta no código. Se a solução for compilada, você saberá que todas as suas consultas estão funcionando. Não há erros de tempo de execução devido a lançamentos ou nomes de colunas inválidos ou consultas inválidas.

Olhando para o dapper, que ainda estamos usando no trabalho, não acredito que em 2016 isso seja a coisa mais legal no acesso a dados. A geração de mensagens em tempo de execução é inteligente, mas todos os erros são erros de tempo de execução, e a manipulação de strings, como a manipulação de strings para qualquer outra finalidade, consome tempo, é frágil e propensa a erros. E como é possível ter que repetir os nomes das colunas no POCO, que você precisa escrever e manter manualmente.

Então lá vai você. Se você quiser ver uma tecnologia desconhecida de acesso a dados de um desenvolvedor desconhecido que trabalha em seu tempo livre (com uma criança pequena e muitos outros hobbies), está aqui .

bbsimonbb
fonte
Você parece pensar muito em sua pequena "inovação", mas como isso é diferente de, digamos, ExecuteStoreQuery ou ExecuteStoreCommand no Entity Framework?
Robert Harvey
Não estou entrando no debate sobre EF ou SQL. A minha coisa é para pessoas que querem usar SQL. Portanto, como uma maneira de executar o SQL, ExecuteStoreQuery () preencherá seus POCOs para você, mas você ainda precisa definir seus POCOs pela aparência. E isso não ajuda em nada a colocar o sql em um arquivo ou a criar seus parâmetros. Sua consulta não pode ser descoberta no código ou testável. A exclusão de colunas não produzirá erros de compilação no seu aplicativo. Eu poderia continuar, mas temo estar me repetindo :-) Talvez você possa levar três minutos para assistir ao vídeo do youtube. É em francês, abaixe o som! Inglês vindo.
bbsimonbb
A EF é capaz de gerar todos os POCOs automaticamente. O que estou perdendo aqui? A verdadeira inovação do Dapper e do Massive é que você não precisa de POCO's; você pode apenas usar dynamic.
Robert Harvey
Não sei quase nada sobre a EF. ExecuteStoreQuery () preencherá uma entidade. Irá gerar uma entidade a partir da consulta . As entidades são geradas a partir de objetos de banco de dados (ou vice-versa), não a partir de consultas. Se sua consulta não corresponde a uma entidade existente, você precisa escrever seu POCO, não?
Bbsimonbb 27/05
1
:-) devo dizer que estou ficando sensível a acusações de publicidade quando estou divulgando minha melhor ideia livremente. Aqui está o meu último pedaço de comercialismo agressivo. Aos 3 minutos, você deve saber se estou em algo ou não.
precisa saber é o seguinte
1

As consultas parametrizadas e o padrão de design do repositório oferecem controle total sobre o que entra na consulta para evitar ataques de injeção. O SQL embutido nesse caso não é um problema que não seja a legibilidade para consultas grandes e complexas, que devem estar nos procedimentos armazenados de qualquer maneira.

Kyle JV
fonte