É considerado um anti-padrão codificar o SQL em um aplicativo como este:
public List<int> getPersonIDs()
{
List<int> listPersonIDs = new List<int>();
using (SqlConnection connection = new SqlConnection(
ConfigurationManager.ConnectionStrings["Connection"].ConnectionString))
using (SqlCommand command = new SqlCommand())
{
command.CommandText = "select id from Person";
command.Connection = connection;
connection.Open();
SqlDataReader datareader = command.ExecuteReader();
while (datareader.Read())
{
listPersonIDs.Add(Convert.ToInt32(datareader["ID"]));
}
}
return listPersonIDs;
}
Normalmente, eu teria uma camada de repositório, etc., mas a excluí no código acima por questões de simplicidade.
Recentemente, recebi alguns comentários de um colega que reclamou que o SQL estava escrito no código-fonte. Não tive chance de perguntar por que e ele está ausente por duas semanas (talvez mais). Suponho que ele quis dizer:
- Use LINQ
ou - Use procedimentos armazenados para o SQL
Estou correcto? É considerado um anti-padrão escrever SQL no código-fonte? Somos uma pequena equipe trabalhando neste projeto. Acho que o benefício dos procedimentos armazenados é que os desenvolvedores do SQL podem se envolver com o processo de desenvolvimento (escrevendo procedimentos armazenados, etc.).
Editar O link a seguir fala sobre instruções SQL codificadas: https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/hard-coded-sql-statements . Existe algum benefício em preparar uma instrução SQL?
Respostas:
Você excluiu a parte crucial da simplicidade. O repositório é a camada de abstração para persistência. Separamos a persistência em sua própria camada, para que possamos alterar a tecnologia de persistência mais facilmente quando necessário. Portanto, ter o SQL fora da camada de persistência frustra completamente o esforço de ter uma camada de persistência separada.
Como resultado: o SQL é bom dentro da camada de persistência específica para uma tecnologia SQL (por exemplo, SQL é bom em um,
SQLCustomerRepository
mas não em umMongoCustomerRepository
). Fora da camada de persistência, o SQL interrompe sua abstração e, portanto, é considerada uma prática muito ruim (por mim).Quanto a ferramentas como LINQ ou JPQL: elas podem apenas abstrair os sabores do SQL por aí. Ter consultas LINQ-Code ou JPQL fora de um repositório interrompe a abstração de persistência tanto quanto o SQL bruto.
Outra grande vantagem de uma camada de persistência separada é que ela permite unittest seu código de lógica de negócios sem a necessidade de configurar um servidor de banco de dados.
Você obtém testes rápidos com baixo perfil de memória e resultados reproduzíveis em todas as plataformas suportadas pelo seu idioma.
Em uma arquitetura MVC + Service, é uma tarefa simples de zombar da instância do repositório, criando alguns dados simulados na memória e definindo que o repositório retorne esses dados simulados quando um determinado getter for chamado. Você pode definir os dados de teste por unittest e não se preocupar com a limpeza do banco de dados posteriormente.
O teste de gravações no banco de dados é tão simples: verifique se os métodos de atualização relevantes na camada de persistência foram chamados e afirme que as entidades estavam no estado correto quando isso aconteceu.
fonte
Hoje, a maioria dos aplicativos de negócios padrão usa camadas diferentes com responsabilidades diferentes. No entanto, quais camadas você usa para seu aplicativo e qual camada possui qual responsabilidade é sua e de sua equipe. Antes de tomar uma decisão sobre se é certo ou errado colocar o SQL diretamente na função que você nos mostrou, precisa saber
qual camada do seu aplicativo tem qual responsabilidade
a partir de qual camada a função acima é de
Não existe uma solução "tamanho único" para isso. Em alguns aplicativos, os designers preferem usar uma estrutura ORM e deixar a estrutura gerar todo o SQL. Em alguns aplicativos, os designers preferem armazenar esse SQL exclusivamente em procedimentos armazenados. Para alguns aplicativos, há uma camada de persistência (ou repositório) escrita à mão onde o SQL vive e, para outros aplicativos, não há problema em definir exceções em determinadas circunstâncias ao colocar estritamente o SQL nessa camada de persistência.
Então o que você precisa pensar sobre: quais camadas você quer ou necessidade em sua aplicação particular, e como você deseja que as responsabilidades? Você escreveu "Eu normalmente teria uma camada de repositório" , mas quais são as responsabilidades exatas que você deseja ter dentro dessa camada e quais responsabilidades deseja colocar em outro lugar? Responda isso primeiro e, em seguida, você poderá responder sua pergunta sozinho.
fonte
Marstato dá uma boa resposta, mas eu gostaria de adicionar mais alguns comentários.
O SQL na fonte NÃO é um anti-padrão, mas pode causar problemas. Lembro-me de quando você costumava colocar consultas SQL nas propriedades dos componentes soltos em todos os formulários. Isso tornou as coisas muito feias muito rápidas e você teve que pular os bastidores para localizar as consultas. Tornei-me um forte defensor da centralização do acesso ao banco de dados, tanto quanto possível, dentro das limitações dos idiomas com os quais estava trabalhando. Seu colega pode estar recebendo flashbacks desses dias sombrios.
Agora, alguns dos comentários estão falando sobre o bloqueio do fornecedor, como se isso fosse automaticamente uma coisa ruim. Não é. Se estou assinando uma verificação de seis dígitos a cada ano para usar o Oracle, você pode apostar que eu quero que qualquer aplicativo que acesse esse banco de dados esteja usando a sintaxe extra do Oracle adequadamentemas ao máximo. Não ficarei feliz se meu banco de dados brilhante estiver aleijado por codificadores que escrevem mal ANSI SQL baunilha quando houver uma "maneira Oracle" de escrever o SQL que não prejudique o banco de dados. Sim, a alteração dos bancos de dados será mais difícil, mas só vi isso em um grande site de clientes algumas vezes em mais de 20 anos e um desses casos foi transferido do DB2 -> Oracle porque o mainframe que hospedava o DB2 estava obsoleto e foi descomissionado . Sim, é um bloqueio do fornecedor, mas para clientes corporativos é realmente desejável pagar por um RDBMS com capacidade cara, como Oracle ou Microsoft SQL Server, e utilizá-lo em toda a extensão. Você tem um contrato de suporte como cobertor de conforto. Se estou pagando por um banco de dados com uma implementação rica de procedimento armazenado,
Isso leva ao próximo ponto: se você está escrevendo um aplicativo que acessa um banco de dados SQL, precisa aprender SQL , bem como a outra linguagem, e aprender, quero dizer otimização de consultas também; Ficarei zangado com você se você escrever código de geração SQL que libere o cache SQL com uma enxurrada de consultas quase idênticas, quando você poderia ter usado uma consulta inteligente e com parâmetros.
Sem desculpas, sem se esconder atrás de um muro do Hibernate. ORMs mal utilizados podem realmente prejudicar o desempenho dos aplicativos. Lembro-me de ter visto uma pergunta no Stack Overflow há alguns anos, seguindo as seguintes linhas:
Que tal "UPDATE table SET field1 = onde field2 é True e Field3> 100". Criar e descartar 250.000 objetos pode muito bem ser seu problema ...
ou seja, ignore o Hibernate quando não for apropriado usá-lo. Entenda o banco de dados.
Portanto, em resumo, a incorporação de SQL no código pode ser uma prática ruim, mas há coisas muito piores que você pode acabar tentando evitar a incorporação de SQL.
fonte
Sim, codificar seqüências de caracteres SQL no código do aplicativo geralmente é um anti-padrão.
Vamos tentar anular a tolerância que desenvolvemos após anos vendo isso no código de produção. Misturar linguagens completamente diferentes com sintaxe diferente no mesmo arquivo geralmente não é uma técnica de desenvolvimento desejável. Isso é diferente das linguagens de gabarito, como o Razor, projetadas para dar significado contextual a vários idiomas. Como Sava B. menciona em um comentário abaixo, o SQL em seu C # ou outra linguagem de aplicativo (Python, C ++ etc.) é uma string como qualquer outra e é semanticamente sem sentido. O mesmo se aplica ao misturar mais de um idioma na maioria dos casos, embora obviamente existam situações em que isso é aceitável, como montagem embutida em C, trechos pequenos e compreensíveis de CSS em HTML (observando que CSS foi projetado para ser misturado com HTML ), e outros.
(Robert C. Martin, sobre mistura de idiomas, Código Limpo , Capítulo 17, "Código Cheiros e Heurísticas", página 288)
Para esta resposta, focarei o SQL (conforme solicitado na pergunta). Os seguintes problemas podem ocorrer ao armazenar o SQL como um conjunto à la carte de seqüências de caracteres desassociadas:
@
prefixo do C # facilita isso, mas vi um monte de código que cita cada linha SQL e escapa às novas linhas."SELECT col1, col2...colN"\ "FROM painfulExample"\ "WHERE maintainability IS NULL"\ "AND modification.effort > @necessary"\
ORMs completos (mapeadores objeto-relacionais como Entity Framework ou Hibernate) podem eliminar SQL aleatoriamente salpicados no código do aplicativo. Meu uso de SQL e arquivos de recursos é apenas um exemplo. ORMs, classes auxiliares etc. podem ajudar a atingir o objetivo de um código mais limpo.
Como Kevin disse em uma resposta anterior, o SQL no código pode ser aceitável em projetos pequenos, mas os projetos grandes começam como projetos pequenos, e a probabilidade de a maioria das equipes voltar e fazer o que é certo muitas vezes é inversamente proporcional ao tamanho do código.
Existem muitas maneiras simples de manter o SQL em um projeto. Um dos métodos que eu costumo usar é colocar cada instrução SQL em um arquivo de recurso do Visual Studio, geralmente chamado "sql". Um arquivo de texto, documento JSON ou outra fonte de dados pode ser razoável, dependendo de suas ferramentas. Em alguns casos, uma classe separada dedicada à instalação de seqüências SQL pode ser a melhor opção, mas pode ter alguns dos problemas descritos acima.
Exemplo SQL: Qual é a aparência mais elegante ?:
Torna-se
O SQL está sempre em um arquivo fácil de localizar ou em um conjunto agrupado de arquivos, cada um com um nome descritivo que descreve o que faz e não como faz, cada um com espaço para um comentário que não interromperá o fluxo do código do aplicativo :
Este método simples executa uma consulta solitária. Na minha experiência, o benefício aumenta à medida que o uso da "língua estrangeira" se torna mais sofisticado. Meu uso de um arquivo de recurso é apenas um exemplo. Métodos diferentes podem ser mais apropriados, dependendo da linguagem (neste caso, SQL) e plataforma.
Este e outros métodos resolvem a lista acima da seguinte maneira:
SQL
.return SqlResource.DoTheThing;
Verdadeiro, essas implementações podem ignorar o recurso e conter o SQL em uma cadeia de caracteres, mas alguns problemas (nem todos) acima ainda apareceriam.sql.GetOrdersForAccount
vez de mais obtusosSELECT ... FROM ... WHERE...
A criação do SQL em um recurso é rápida, portanto, há pouco impulso para misturar o uso de recursos com o SQL-in-code.
Independentemente do método escolhido, descobri que a mistura de linguagens geralmente reduz a qualidade do código. Espero que alguns problemas e soluções descritos aqui ajudem os desenvolvedores a eliminar esse cheiro de código, quando apropriado.
fonte
Depende. Existem várias abordagens diferentes que podem funcionar:
Como geralmente ocorre, se o seu projeto já escolheu uma dessas técnicas, você deve ser consistente com o restante do projeto.
(1) e (3) são relativamente bons em manter a independência entre a lógica do aplicativo e o banco de dados, no sentido de que o aplicativo continuará a compilar e passar nos testes básicos de fumaça se você substituir o banco de dados por um fornecedor diferente. No entanto, a maioria dos fornecedores não está totalmente em conformidade com o padrão SQL; portanto, a substituição de qualquer fornecedor por qualquer outro fornecedor provavelmente requer testes extensivos e busca de bugs, independentemente da técnica usada. Estou cético de que isso seja tão importante quanto as pessoas pensam ser. A alteração dos bancos de dados é basicamente o último recurso quando você não pode obter o banco de dados atual para atender às suas necessidades. Se isso acontecer, você provavelmente escolheu mal o banco de dados.
A escolha entre (1) e (3) é principalmente uma questão de quanto você gosta de ORMs. Na minha opinião, eles são usados em excesso. Eles são uma representação ruim do modelo de dados relacionais, porque as linhas não têm identidade da maneira que os objetos têm identidade. É provável que você encontre pontos problemáticos em torno de restrições e uniões únicas e poderá ter dificuldade para expressar algumas consultas mais complicadas, dependendo do poder do ORM. Por outro lado, (1) provavelmente exigirá significativamente mais código do que um ORM.
(2) é raramente visto, na minha experiência. O problema é que muitas lojas proíbem os SWEs de modificar diretamente o esquema do banco de dados (porque "esse é o trabalho do DBA"). Isso não é necessariamente uma coisa ruim em si; as alterações de esquema têm um potencial significativo para quebrar coisas e podem precisar ser implementadas com cuidado. No entanto, para que (2) funcione, os SWEs devem pelo menos poder introduzir novas visões e modificar as consultas de suporte das visões existentes com pouca ou nenhuma burocracia. Se não for esse o caso no seu local de trabalho, (2) provavelmente não funcionará para você.
Por outro lado, se você conseguir fazer o (2) funcionar, é muito melhor que a maioria das outras soluções, pois mantém a lógica relacional no SQL, em vez do código do aplicativo. Diferentemente das linguagens de programação de uso geral, o SQL é projetado especificamente para o modelo de dados relacionais e, portanto, é melhor para expressar consultas e transformações complicadas de dados. As visualizações também podem ser portadas junto com o restante do esquema ao alterar os bancos de dados, mas elas tornarão essas mudanças mais complicadas.
Para leituras, os procedimentos armazenados são basicamente apenas uma versão de baixa qualidade de (2). Eu não os recomendo nessa capacidade, mas você ainda pode desejá-los para gravações, se seu banco de dados não suportar visualizações atualizáveis ou se precisar fazer algo mais complexo do que inserir ou atualizar uma única linha de cada vez (por exemplo, transações, leitura e gravação etc.). Você pode acoplar seu procedimento armazenado a uma exibição usando um gatilho (por exemplo,
CREATE TRIGGER trigger_name INSTEAD OF INSERT ON view_name FOR EACH ROW EXECUTE PROCEDURE procedure_name;
), mas as opiniões variam consideravelmente sobre se essa é realmente uma boa ideia. Os proponentes dirão que ele mantém o SQL que seu aplicativo executa da maneira mais simples possível. Os detratores dirão que esse é um nível inaceitável de "mágica" e que você deve apenas executar o procedimento diretamente do seu aplicativo. Eu diria que esta é uma idéia melhor se o seu procedimento armazenado parece ou age muito parecido com umINSERT
,UPDATE
ouDELETE
, e uma ideia pior se ele está fazendo outra coisa. Por fim, você terá que decidir por si mesmo qual estilo faz mais sentido.(4) é a não solução. Pode valer a pena para projetos pequenos ou grandes que apenas interagem esporadicamente com o banco de dados. Mas para projetos com muito SQL, não é uma boa ideia, pois você pode ter duplicatas ou variações da mesma consulta espalhadas aleatoriamente em seu aplicativo, o que interfere na legibilidade e na refatoração.
fonte
Não necessariamente. Se você ler todos os comentários aqui, encontrará argumentos válidos para codificar instruções SQL no código-fonte.
O problema vem com o local em que você coloca as declarações . Se você colocar as instruções SQL em todo o projeto, em qualquer lugar, provavelmente estará ignorando alguns dos princípios do SOLID que normalmente nos esforçamos para seguir.
Não podemos dizer o que ele quis dizer. No entanto, podemos adivinhar. Por exemplo, o primeiro que me vem à mente é o aprisionamento de fornecedores . As instruções SQL codificadas podem levar você a associar firmemente seu aplicativo ao mecanismo de banco de dados. Por exemplo, usando funções específicas do fornecedor que não são compatíveis com ANSI.
Isso não é necessariamente errado nem ruim. Estou apenas apontando para o fato.
Ignorar os princípios do SOLID e os bloqueios do fornecedor tem possíveis consequências adversas que você pode estar ignorando. É por isso que geralmente é bom sentar com a equipe e expor suas dúvidas.
Eu acho que não tem nada a ver com as vantagens dos procedimentos armazenados. Além disso, se o seu colega não gostar de SQL codificado, é provável que você mude os negócios para procedimentos armazenados também não gostará dele.
Sim. O post enumera as vantagens de declarações preparadas . É uma espécie de modelagem SQL. Mais seguro que a concatenação de strings. Mas o post não está incentivando você a seguir esse caminho nem confirmando que você está certo. Apenas explica como podemos usar o SQL codificado de maneira segura e eficiente.
Resumindo, tente perguntar ao seu colega primeiro. Envie um e-mail, ligue para ele, ... Se ele responde ou não, sente-se com a equipe e exponha suas dúvidas. Encontre a solução que melhor atenda às suas necessidades. Não faça suposições falsas com base no que você lê por aí.
fonte
select GETDATE(), ....
GETDATE () é a função de data do SqlServer. Em outras enginees, a função tem nome diferente, expressão diferente, ...Eu acho que é uma prática ruim, sim. Outros apontaram as vantagens de manter todo o seu código de acesso a dados em sua própria camada. Você não precisa procurar por isso, é mais fácil otimizar e testar ... Mas mesmo nessa camada, você tem algumas opções: usar um ORM, usar sprocs ou incorporar consultas SQL como strings. Eu diria que as strings de consulta SQL são de longe a pior opção.
Com um ORM, o desenvolvimento se torna muito mais fácil e menos propenso a erros. Com o EF, você define seu esquema apenas criando suas classes de modelo (você precisaria criar essas classes de qualquer maneira). Consultar com LINQ é fácil - você costuma sair com duas linhas de c # onde seria necessário escrever e manter um sproc. Na IMO, isso tem uma enorme vantagem quando se trata de produtividade e manutenção - menos código, menos problemas. Mas há uma sobrecarga de desempenho, mesmo se você souber o que está fazendo.
Sprocs (ou funções) são a outra opção. Aqui, você escreve suas consultas SQL manualmente. Mas pelo menos você tem alguma garantia de que eles estão corretos. Se você estiver trabalhando no .NET, o Visual Studio lançará erros de compilador se o SQL for inválido. Isso é ótimo. Se você alterar ou remover alguma coluna e algumas de suas consultas se tornarem inválidas, é provável que você descubra isso durante o tempo de compilação. Também é muito mais fácil manter sprocs em seus próprios arquivos - você provavelmente terá destaque de sintaxe, preenchimento automático ... etc.
Se suas consultas forem armazenadas como sprocs, você também poderá alterá-las sem recompilar e reimplementar o aplicativo. Se você perceber que algo no seu SQL está quebrado, um DBA pode corrigi-lo sem precisar ter acesso ao código do aplicativo. Em geral, se suas consultas estão em literais de string, você não pode fazer o trabalho deles com a mesma facilidade.
As consultas SQL como literais de strings também tornarão seu código c # de acesso a dados menos legível.
Como regra geral, constantes mágicas são ruins. Isso inclui literais de string.
fonte
Não é um antipadrão (esta resposta está perigosamente próxima da opinião). Mas a formatação do código é importante, e a string SQL deve ser formatada para que fique claramente separada do código que a utiliza. Por exemplo
fonte
Não posso lhe dizer o que seu colega quis dizer. Mas eu posso responder isso:
SIM . O uso de instruções preparadas com variáveis associadas é a defesa recomendada contra a injeção de SQL , que continua sendo o maior risco de segurança para aplicativos da web há mais de uma década . Esse ataque é tão comum que foi apresentado nos quadrinhos da web quase dez anos atrás, e é hora de defender defesas eficazes.
... e a defesa mais eficaz contra concatenação incorreta de cadeias de caracteres de consulta não representa consultas como cadeias de caracteres em primeiro lugar, mas para usar uma API de consulta de tipo seguro para criar consultas. Por exemplo, aqui está como eu escreveria sua consulta em Java com QueryDSL:
Como você pode ver, não há uma única string literal aqui, tornando impossível a injeção de SQL. Além disso, eu tive o preenchimento de código ao escrever isso, e meu IDE pode refatorá-lo, caso eu escolha renomear a coluna id. Além disso, posso encontrar facilmente todas as consultas da tabela de pessoas perguntando ao meu IDE onde a
person
variável é acessada. Ah, e você notou que é um pouco mais curto e fácil aos olhos do que o seu código?Só posso supor que algo assim também esteja disponível para C #. Por exemplo, ouço grandes coisas sobre o LINQ.
Em resumo, representar consultas como seqüências de caracteres SQL torna difícil para o IDE ajudar significativamente na gravação e refatoração de consultas, adia a detecção de erros de sintaxe e tipo do tempo de compilação para o tempo de execução e é uma causa contribuinte para as vulnerabilidades de injeção SQL [1]. Portanto, sim, existem razões válidas pelas quais alguém pode não querer seqüências de caracteres SQL no código-fonte.
[1]: Sim, o uso correto de instruções preparadas também evita a injeção de SQL. Mas essa outra resposta neste segmento ficou vulnerável a uma injeção de SQL até que um comentarista apontou isso não inspira confiança nos programadores juniores que os usassem corretamente sempre que necessário ...
fonte
Muitas ótimas respostas aqui. Além do que já foi dito, gostaria de acrescentar mais uma coisa.
Não considero o uso de SQL embutido um anti-padrão. No entanto, o que considero um antipadrão é todo programador fazendo suas próprias coisas. Você precisa decidir em equipe um padrão comum. Se todo mundo estiver usando o linq, use linq; se todo mundo estiver usando visualizações e procedimentos armazenados, faça isso.
Mas mantenha sempre a mente aberta e não caia no dogma. Se sua loja é uma loja "linq", você a usa. Exceto por aquele lugar em que o linq absolutamente não funciona. (Mas você não deve 99,9% do tempo.)
Então, o que eu faria é pesquisar o código na base de código e verificar como seus colegas trabalham.
fonte
O código se parece com a camada de interação com o banco de dados que está entre o banco de dados e o restante do código. Se realmente for, isso não é anti-padrão.
Esse método é a parte da camada, mesmo que o OP pense de maneira diferente (acesso simples ao banco de dados, sem misturar com mais nada). Talvez seja apenas mal colocado dentro do código. Este método pertence à classe separada, "camada de interface do banco de dados". Seria antipadrão colocá-lo dentro da classe comum ao lado dos métodos que implementam atividades que não são de banco de dados.
O anti-padrão seria chamar SQL de algum outro local aleatório de código. Você precisa definir uma camada entre o banco de dados e o restante do código, mas não é necessário usar absolutamente alguma ferramenta popular que possa ajudá-lo lá.
fonte
Na minha opinião, não é um anti-padrão, mas você se encontrará lidando com o espaçamento da formatação de string, especialmente para grandes consultas que não cabem em uma linha.
outro profissional é que fica muito mais difícil lidar com consultas dinâmicas que devem ser criadas de acordo com certas condições.
Eu sugiro usar um construtor de consultas sql
fonte
Para muitas organizações modernas com pipelines de implantação rápida em que as alterações de código podem ser compiladas, testadas e colocadas em produção em minutos, faz todo o sentido incorporar instruções SQL ao código do aplicativo. Isso não é necessariamente um anti-padrão, dependendo de como você o faz.
Hoje, um caso válido para o uso de procedimentos armazenados está em organizações nas quais há muito processo em torno das implantações de produção que podem envolver semanas de ciclos de controle de qualidade etc. Nesse cenário, a equipe do DBA pode resolver problemas de desempenho que surgem somente após a implantação inicial da produção, otimizando as consultas nos procedimentos armazenados.
A menos que você esteja nessa situação, recomendo que você incorpore seu SQL ao código do aplicativo. Leia outras respostas neste tópico para obter conselhos sobre a melhor maneira de fazê-lo.
Texto original abaixo para contexto
A principal vantagem dos procedimentos armazenados é que você pode otimizar o desempenho do banco de dados sem recompilar e reimplementar seu aplicativo.
Em muitas organizações, o código só pode ser enviado para produção após um ciclo de controle de qualidade, etc., que pode levar dias ou semanas. Se o seu sistema desenvolver um problema de desempenho do banco de dados devido a alterações nos padrões de uso ou aumentos nos tamanhos das tabelas, etc., pode ser bastante difícil rastrear o problema com consultas codificadas, enquanto o banco de dados terá ferramentas / relatórios, etc., que identificarão procedimentos armazenados com problemas . Com os procedimentos armazenados, as soluções podem ser testadas / comparadas na produção e o problema pode ser corrigido rapidamente, sem a necessidade de enviar uma nova versão do software aplicativo.
Se esse problema não for importante no sistema, é uma decisão perfeitamente válida para codificar instruções SQL no aplicativo.
fonte