Best practice per eseguire query sui dati da MS SQL Server in C #?


9

Qual è il modo migliore per interrogare i dati da un MS SQL Server in C #?

So che non è buona norma avere una query SQL nel codice.

È il modo migliore per creare una procedura memorizzata e chiamarla da C # con parametri?

using (var conn = new SqlConnection(connStr))
using (var command = new SqlCommand("StoredProc", conn) { CommandType = CommandType.StoredProcedure }) {
   conn.Open();
   command.ExecuteNonQuery();
   conn.Close();
}

8
"So che non è buona norma avere una query SQL nel codice." - imo, questa è una sciocchezza.
GrandmasterB,

4
Non è necessario chiamare conn.Close () se è stato creato in un blocco using. Il punto centrale del blocco utilizzando è imitare lo stile C ++ di pulizia del distruttore. Una pulizia elegante da un'età più civile. Non casuale o goffo come lo stile di prova.
Lord Tydus,

2
FYI. Le procedure memorizzate sono anche "codice". Il punto centrale dei proc memorizzati era consentire la miscelazione di codice procedurale con stile SQL basato su set. Quindi avrai una query nel codice a prescindere. Per app di volume estremamente elevato, a volte è meglio eseguire la logica all'esterno del database per consentire il ridimensionamento orizzontale aggiungendo server. Se riesci a mantenere un singolo DB, ma muli-server per la logica, il ridimensionamento diventa molto più semplice.
Lord Tydus,

@GrandmasterB abbiamo una notevole quantità di SQL inline in C # (il nostro C # LOC è quasi 2 milioni ora) - e 6 anni dopo tornerà a morderci perché ora abbiamo bisogno di dare la caccia a quel SQL inline (recentemente abbiamo assunto un esperto SQL - quindi stiamo apportando modifiche alle prestazioni). Fidati di me: non sai mai quanto sarà grande la tua app e come le cose cambieranno in futuro. Mantieni lingue diverse in file diversi, anche se lo deleghi a manifest risorse. Potresti anche // SQLCODEfarlo - ma devi ricordarti di farlo.
Jonathan Dickinson,

1
@JonathanDickinson, se vuoi, usa i processi memorizzati. Ho detto molte volte che sono utili quando si hanno basi di codice disparate che operano sullo stesso database. Ma solo perché sono utili in alcune circostanze pretende molto automaticamente rendono non li utilizzano 'cattiva pratica' per tutto il tempo . Se l'utilizzo diretto delle istruzioni SQL non causa problemi, non è una "cattiva pratica" per quell'app.
GrandmasterB,

Risposte:


10

L'uso di stored procedure è un modo ed è stato ampiamente utilizzato per molti anni.

Un modo più moderno di interagire con i database di SQL Server da C # (o qualsiasi linguaggio .NET) consiste nell'utilizzare Entity Framework. Il vantaggio di Entity Framework è che fornisce un livello più elevato di astrazione.

Per citare da Microsoft ( https://msdn.microsoft.com/en-us/data/jj590134 ):

ADO.NET Entity Framework consente agli sviluppatori di creare applicazioni di accesso ai dati programmando su un modello di applicazione concettuale invece di programmare direttamente su uno schema di archiviazione relazionale. L'obiettivo è ridurre la quantità di codice e manutenzione richiesta per le applicazioni orientate ai dati. Le applicazioni Entity Framework offrono i seguenti vantaggi:

  • Le applicazioni possono funzionare in termini di un modello concettuale più incentrato sull'applicazione, inclusi tipi con ereditarietà, membri complessi e relazioni.
  • Le applicazioni vengono liberate da dipendenze codificate su un determinato motore di dati o schema di archiviazione.
  • Le mappature tra il modello concettuale e lo schema specifico di archiviazione possono cambiare senza cambiare il codice dell'applicazione.
  • Gli sviluppatori possono lavorare con un modello a oggetti di applicazione coerente che può essere mappato a vari schemi di archiviazione, eventualmente implementati in diversi sistemi di gestione del database.
  • Più modelli concettuali possono essere associati a un singolo schema di archiviazione.
  • Il supporto per le query integrate nella lingua (LINQ) fornisce la convalida della sintassi in fase di compilazione per le query rispetto a un modello concettuale.

L'uso di un ORM vs Stored procedure comporta compromessi, in particolare in termini di sicurezza e in cui risiede la logica.

L'approccio "classico" allo sviluppo con SQL Server consiste nel far sì che la logica dell'applicazione risieda nelle procedure e nei programmi memorizzati solo ai diritti di sicurezza per eseguire le procedure memorizzate, non all'aggiornamento diretto delle tabelle. Il concetto qui è che le stored procedure sono il livello di logica aziendale per le applicazioni. Sebbene la teoria sia valida, tende a sfuggire al favore per vari motivi, sostituendosi con l'implementazione della logica di business in un linguaggio di programmazione come C # o VB. Le buone applicazioni sono ancora implementate con un approccio a più livelli, inclusa la separazione delle preoccupazioni ecc., Ma hanno maggiori probabilità di seguire uno schema come MVC.

Un aspetto negativo dell'implementazione della logica nell'ORM piuttosto che nel database è la facilità di debug e test delle regole di integrità dei dati da parte dei responsabili del database (DA o DBA). Prendiamo il classico esempio di trasferimento di denaro dal conto corrente al conto di risparmio, è importante che ciò avvenga come unità di lavoro atomica, in altre parole inserita in una transazione. Se questo tipo di trasferimento può essere eseguito solo attraverso una procedura memorizzata, è relativamente facile per il procuratore generale e gli auditor eseguire la procedura memorizzata.

Se d'altra parte ciò avviene tramite un ORM come Entity Framework e nella produzione si scopre che in rare occasioni il denaro viene prelevato dal controllo ma non messo nel risparmio il debug può essere molto più complesso, in particolare se sono potenzialmente coinvolti più programmi. Questo sarebbe molto probabilmente un caso limite, che potrebbe comportare particolari problemi hardware che devono verificarsi in una sequenza particolare, ecc. Come si fa a testarlo?


O altri ORM. Ce ne sono molti, con vari vantaggi e svantaggi rispetto a EF.
svick,

8
Elencare gli svantaggi degli ORM renderebbe questa risposta più utile.
Den

6

In realtà l'asserzione di base è discutibile - ci sono dei compromessi in entrambi i casi tra avere SQL nel codice o avere codice nel database (che è dove ti stai dirigendo con le procedure memorizzate).

Il risultato è che non esiste un unico "migliore", questo non è qualcosa che si può generalizzare perché in qualunque modo si sta facendo un compromesso (si ottengono benefici ma si introducono anche vincoli).

Se esiste una corrispondenza uno a uno tra l'applicazione e il database, non importa. Se, d'altra parte, si dispone di un ampio database core condiviso da un numero significativo di applicazioni che garantiscono coerenza all'interno del database tra tali applicazioni diventa molto più importante.

La cosa più importante è preoccuparsi dell'architettura e della stratificazione della tua applicazione - dato un livello di accesso ai dati appropriato sia che usi un ORM come Entity Framework o NHibernate o che faccia qualcosa di più diretto, dovresti isolare la maggior parte della tua applicazione da questa decisione, indipendentemente dal fatto che tu crei query o utilizzare le procedure memorizzate.


Avrei liberamente teso a lavorare su progetti relativamente piccoli con piccoli team (1-3 sviluppatori) - l'utilizzo di procedure memorizzate è, per me, più problemi del suo valore perché, data la natura delle nostre applicazioni (e il mio skillset?), Implementando nuove il codice è generalmente molto più semplice dell'aggiornamento dello schema (anche consentendo di disporre di un codice che renda relativamente semplice l'aggiornamento dello schema) e sono in grado di applicare le regole di business utilizzando un codice di accesso ai dati comune. Questo è chiaramente un classico esempio di "Il tuo chilometraggio può variare".


2
+1 per "nessun singolo migliore", -1 per la distribuzione del codice è più semplice della distribuzione delle modifiche ai proc memorizzati, +1 per la scelta di un approccio che ha senso per la tua app e garantisce l'isolamento DAL - Quindi +1.
Joel Brown,

Ho qualificato il bit di distribuzione con "per me" perché questo è stato per me il caso costante (specialmente per le applicazioni Web) - per tutto ciò che potrebbe comportare un po 'di riscrittura in quell'area.
Murph,

+1, ciò che meglio dipende dall'applicazione e dalla situazione.
GrandmasterB,

1
Immagino che dipenda dalle condizioni in cui lavori. Se non hai DBA che ti bloccano fuori produzione, far cadere un proc memorizzato sostitutivo nel database può essere spaventosamente facile. Del resto, senza i controlli di produzione che possono far cadere nuovi markup, script e persino nuovi codici compilati in un'app centralizzata possono essere troppo facili.
Joel Brown,

@JoelBrown - Esatto - Suppongo di no, sono certo di aver fatto un sacco di ipotesi lì. Innanzitutto il mio schema è controllato dalla versione (in modo rozzo ma efficace), non sono un dba ma sono abbastanza intelligente da sapere che il proprio schema deve essere coerente. Lavoro principalmente su app Web e non puoi accedere ai database se non visitando il server, mentre ho (solo) ridotto la distribuzione di app a (più o meno) un solo pulsante ... integrando gli aggiornamenti dello schema in detto la distribuzione è nella lista, ma ho sempre trovato gli aggiornamenti dello schema più stressanti degli aggiornamenti del codice (facilità di rollback?)
Murph

4

Finché hai parametrizzato i tuoi input, ogni approccio è valido. Gran parte del non avere domande negli argomenti del codice proveniva dai brutti vecchi tempi in cui molte delle biblioteche ti costringevano ad aggiungere stringhe le tue dichiarazioni insieme ed è da lì che provenivano gli attacchi di iniezione sql.


1
La parametrizzazione è sufficiente? Non hai bisogno di disinfettare anche tu?
Stuper:

dipende dalla tua fonte e dal tuo scopo. Stavo prendendo letteralmente la sua domanda, è di sola lettura con alcuni parametri. nei casi più comuni il peggio che si farebbe con un input sporco se correttamente parametrizzato è ottenere un'eccezione di tipo o nessun risultato con un input errato. L'inserimento è diverso e di solito necessita di convalida a meno che tu non consideri la fonte come autorevole.
Bill

0

Le migliori pratiche qui sono davvero esagerate - ci sono molti buoni modi per farlo e quello che scegli davvero dovrebbe dipendere da cosa è la tua app e cosa devi fare. Detto questo, ci sono solo due cose che puoi fare davvero di sbagliato:

  • Come sottolinea @Bill, dovresti sempre parametrizzare le tue query. La creazione di stringhe è un vettore semplice per l'iniezione di SQL e tutti i tipi di bug difficili da rintracciare. Le persone molto più intelligenti hanno capito come tupelizzare e sfuggire a sql, quindi non è necessario capirlo da soli.

  • Chiudi le tue connessioni. Il modo migliore è racchiudere tutto in un'istruzione using, ma provare / catturare / finalmente è anche bello se questo fa galleggiare la tua barca. Ma assicurati sempre di utilizzare una connessione come un'auto economica: guidala forte e veloce e sbarazzati di essa rapidamente.

L'altra pratica per la quale vorrei contestare con veemenza è che dovresti assicurarti di concentrare il codice di accesso ai dati nel minor numero di posti possibile. Non consentiamo alle app Web front-end di contenere un riferimento diretto a System.Data.SqlClient per aiutare a far rispettare questo avvertimento.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.