Prática recomendada para consultar dados do MS SQL Server em C #?

9

Qual é a melhor maneira de consultar dados de um MS SQL Server em C #?

Eu sei que não é uma boa prática ter uma consulta SQL no código.

É a melhor maneira de criar um procedimento armazenado e chamá-lo de C # com parâmetros?

using (var conn = new SqlConnection(connStr))
using (var command = new SqlCommand("StoredProc", conn) { CommandType = CommandType.StoredProcedure }) {
   conn.Open();
   command.ExecuteNonQuery();
   conn.Close();
}
Bruno
fonte
8
"Eu sei que não é uma boa prática ter uma consulta SQL no código." - imo, isso é um absurdo.
GrandmasterB
4
Você não precisa chamar conn.Close () se você o criou em um bloco using. O objetivo principal do bloco using é imitar o estilo C ++ de limpeza de destruidores. Uma limpeza elegante a partir de uma era mais civilizada. Não é tão aleatório ou desajeitado quanto o estilo try-catch.
Lord Tydus
2
PARA SUA INFORMAÇÃO. Os procedimentos armazenados também são "código". O objetivo principal dos procs armazenados era permitir a mistura de código processual com o estilo SQL baseado em conjunto. Portanto, você terá uma consulta no código independentemente. Para aplicativos de volume extremamente alto, às vezes é melhor executar a lógica fora do banco de dados para permitir o dimensionamento horizontal adicionando servidores. Se você pode manter um único banco de dados, mas com vários servidores para a lógica, o dimensionamento se torna muito mais fácil.
Lord Tydus
@GrandmasterB, temos uma quantidade substancial de SQL inline em C # (nosso C # LOC está perto de 2 milhões agora) - e 6 anos depois ele volta a nos morder, porque agora precisamos caçar esse SQL inline (recentemente contratamos um especialista em SQL - então estamos fazendo ajustes no desempenho). Confie em mim: você nunca sabe o tamanho do seu aplicativo e como as coisas vão mudar no futuro. Mantenha idiomas diferentes em arquivos diferentes - mesmo que você o delegue para manifestar recursos. Você também pode // SQLCODE- mas precisa se lembrar de fazer isso.
Jonathan Dickinson
11
@ JonathanDickinson, use procs armazenados, se quiser. Eu disse muitas vezes que são úteis quando você tem bases de código diferentes operando no mesmo banco de dados. Mas só porque eles são úteis em algumas circunstâncias does not fazer automaticamente não usá-los 'má prática' o tempo todo . Se o uso direto de instruções SQL não estiver causando problemas, isso não é uma "má prática" para esse aplicativo.
GrandmasterB

Respostas:

10

O uso de procedimentos armazenados é uma maneira e tem sido amplamente utilizado por muitos anos.

Uma maneira mais moderna de interagir com os bancos de dados do SQL Server a partir de C # (ou qualquer linguagem .NET) é usar o Entity Framework. A vantagem do Entity Framework é que ele fornece um nível mais alto de abstração.

Para citar a Microsoft ( https://msdn.microsoft.com/en-us/data/jj590134 ):

O ADO.NET Entity Framework permite que os desenvolvedores criem aplicativos de acesso a dados programando em um modelo de aplicativo conceitual em vez de programar diretamente em um esquema de armazenamento relacional. O objetivo é diminuir a quantidade de código e manutenção necessária para aplicativos orientados a dados. Os aplicativos do Entity Framework fornecem os seguintes benefícios:

  • Os aplicativos podem funcionar em termos de um modelo conceitual mais centrado em aplicativos, incluindo tipos com herança, membros complexos e relacionamentos.
  • Os aplicativos são liberados de dependências codificadas em um mecanismo de dados ou esquema de armazenamento específico.
  • Os mapeamentos entre o modelo conceitual e o esquema específico do armazenamento podem mudar sem alterar o código do aplicativo.
  • Os desenvolvedores podem trabalhar com um modelo de objeto de aplicativo consistente que pode ser mapeado para vários esquemas de armazenamento, possivelmente implementados em diferentes sistemas de gerenciamento de banco de dados.
  • Vários modelos conceituais podem ser mapeados para um único esquema de armazenamento.
  • O suporte a consulta integrada à linguagem (LINQ) fornece validação de sintaxe em tempo de compilação para consultas em relação a um modelo conceitual.

O uso de um ORM vs procedimentos armazenados envolve compensações, principalmente em termos de segurança e onde a lógica reside.

A abordagem "clássica" ao desenvolvimento com o SQL Server é fazer com que a lógica do aplicativo resida nos procedimentos e programas armazenados, apenas com direitos de segurança para executar procedimentos armazenados, não para atualizar tabelas diretamente. O conceito aqui é que os procedimentos armazenados são a camada de lógica de negócios para os aplicativos. Embora a teoria seja sólida, ela tende a perder o interesse por várias razões, sendo substituída pela implementação da lógica de negócios em uma linguagem de programação como C # ou VB. Bons aplicativos ainda são implementados com uma abordagem em camadas, incluindo a separação de preocupações etc., mas são mais propensos a seguir um padrão como o MVC.

Uma desvantagem da implementação da lógica no ORM, e não no banco de dados, é a facilidade de depuração e teste das regras de integridade de dados pelos responsáveis ​​pelo banco de dados (DA ou DBA). Pegue o exemplo clássico de transferência de dinheiro da sua conta corrente para a conta poupança, é importante que isso seja feito como uma unidade atômica de trabalho, ou seja, imprensado em uma transação. Se esse tipo de transferência apenas pode ser realizado por meio de um procedimento armazenado, é relativamente fácil para o DA e os auditores controlarem o controle do controle por controle de qualidade.

Se, por outro lado, isso é feito por meio de um ORM como o Entity Framework e na produção, é descoberto que, em raras ocasiões, o dinheiro é retirado da verificação, mas não colocado na depuração da economia, pode ser muito mais complexo, principalmente se vários programas estiverem potencialmente envolvidos. Provavelmente, esse seria um caso extremo, talvez envolvendo problemas peculiares de hardware que precisam ocorrer em uma sequência específica etc. Como testar isso?

JonnyBoats
fonte
Ou outro ORM. Existem muitos deles, com várias vantagens e desvantagens quando comparados com o EF.
svick
8
Listar as desvantagens dos ORMs tornaria essa resposta mais útil.
Den
6

Na verdade, a asserção básica é discutível - existem trocas entre o SQL no código ou o código no banco de dados (que é onde você está seguindo os procedimentos armazenados).

O resultado é que não existe um "melhor" único, isso não é algo que você pode generalizar, porque, por qualquer caminho que você vá, você está comprometendo (você obtém benefícios, mas também introduz restrições).

Se houver uma correspondência individual entre o aplicativo e o banco de dados, isso realmente não importa. Se, por outro lado, você tiver um grande banco de dados núcleo compartilhado por um número significativo de aplicativos que impõem consistência no banco de dados entre esses aplicativos, isso se tornará muito mais importante.

O mais importante é se preocupar com a arquitetura e as camadas do seu aplicativo - considerando uma camada de acesso a dados apropriada, usar um ORM como o Entity Framework ou NHibernate ou fazer algo mais direto deve isolar a maioria do seu aplicativo desta decisão, independentemente de você criar consultas ou use procedimentos armazenados.


Terei a liberdade de trabalhar em projetos relativamente pequenos com equipes pequenas (1-3 desenvolvedores) - usar procedimentos armazenados é, para mim, mais problemas do que vale a pena, porque, dada a natureza de nossos aplicativos (e meu conjunto de habilidades?) o código geralmente é muito mais fácil do que atualizar o esquema (mesmo permitindo que eu tenha um código que torne a atualização relativamente simples) e que eu possa impor regras de negócios usando o código comum de acesso a dados. Este é claramente um exemplo clássico de "Sua milhagem pode variar".

Murph
fonte
2
+1 para "não é o melhor", -1 para implantar código é mais fácil do que implantar alterações de proc armazenadas, +1 para escolher uma abordagem que faça sentido para seu aplicativo e garanta o isolamento do DAL - então +1.
Joel Brown
Eu qualifiquei o bit de implantação com "for me", porque esse sempre foi o meu caso (especialmente para aplicativos da web) - por tudo o que pode ser um pouco reescrito nessa área.
Murph 21/01
+1, o que é melhor depende da aplicação e da situação.
GrandmasterB
11
Acho que depende das condições em que você trabalha. Se você não tem DBAs bloqueando sua produção, soltar um proc armazenado de substituição no banco de dados pode ser assustadoramente fácil. Nesse caso, sem que os controles de produção descartem novas marcações, scripts e até mesmo novos códigos compilados em um aplicativo centralizado também podem ser fáceis demais.
Joel Brown
@JoelBrown - Exatamente - Suponho que não, tenho certeza de que fiz uma série de suposições por lá. Em primeiro lugar, meu esquema é controlado por versão (de uma maneira rudimentar, mas eficaz), não sou dba, mas sou inteligente o suficiente para saber que o esquema de alguém precisa ser consistente. Eu trabalho principalmente em aplicativos da Web e você não pode acessar os bancos de dados, exceto visitando o servidor, enquanto eu (apenas) reduzi a implantação de aplicativos para (mais ou menos) um clique em um único botão ... integrando atualizações de esquema ao referido implantação está na lista, mas tenho sempre encontrado atualizações de esquema mais estressante do que atualizações de código (facilidade de reversão?)
Murph
4

Desde que você tenha parametrizado suas entradas, qualquer abordagem é válida. Muitos dos que não têm consultas nos argumentos de código vieram dos velhos tempos ruins, quando muitas das bibliotecas o obrigaram a anexar suas instruções por string e é daí que os ataques de injeção de sql vieram.

Conta
fonte
11
Parametrizar é suficiente? Você não precisa higienizar também?
StuperUser
isso depende da sua fonte e do seu propósito. Eu estava aceitando sua pergunta literalmente, ele é somente leitura com alguns parâmetros. em casos comuns, o pior que você faria com a entrada suja se parametrizado corretamente é obter uma exceção de tipo ou nenhum resultado com entrada incorreta. A inserção é diferente e geralmente precisa de validação, a menos que você trate a fonte como autorizada.
Bill
0

As práticas recomendadas são realmente exageradas aqui - há muitas maneiras boas de fazer isso e a que você escolhe deve depender do que é seu aplicativo e do que você precisa fazer. Dito isto, existem apenas duas coisas que você pode fazer realmente errado:

  • Como o @Bill aponta, você deve sempre parametrizar suas consultas. A criação de strings é um vetor fácil para injeção de SQL, além de todo tipo de erros difíceis de rastrear. Pessoas muito mais inteligentes descobriram como tupelizar e escapar do sql para que você não precise descobrir sozinho.

  • Feche suas conexões. A melhor maneira é envolver tudo em uma declaração de uso, mas try / catch / finalmente também é legal se isso flutua no seu barco. Mas sempre use uma conexão como um carro barato - conduza com força e rapidez e livre-se dela rapidamente.

A outra prática pela qual eu argumentaria veementemente é que você deve se concentrar no código de acesso a dados no menor número possível de lugares. Não permitimos que aplicativos Web front-end mantenham uma referência direta ao System.Data.SqlClient para ajudar a impor essa advertência.

Wyatt Barnett
fonte