.NET Framework
ADO.NET
Ricerca…
introduzione
ADO (ActiveX Data Objects) .Net è uno strumento fornito da Microsoft che fornisce l'accesso a origini dati quali SQL Server, Oracle e XML attraverso i suoi componenti. Le applicazioni front-end .Net possono recuperare, creare e manipolare i dati, una volta connessi a un'origine dati tramite ADO.Net con i privilegi appropriati.
ADO.Net fornisce un'architettura senza connessione. È un approccio sicuro per interagire con un database, poiché la connessione non deve essere mantenuta durante l'intera sessione.
Osservazioni
Una nota sulla parametrizzazione di SQL con Parameters.AddWithValue
: AddWithValue
non è mai un buon punto di partenza. Questo metodo si basa sulla deduzione del tipo di dati da ciò che viene passato. Con questo, si potrebbe finire in una situazione in cui la conversione impedisce alla query di utilizzare un indice . Si noti che alcuni tipi di dati di SQL Server, come char
/ varchar
(senza precedente "n") o date
, non hanno un tipo di dati .NET corrispondente. In questi casi, è necessario utilizzare Add
con il tipo di dati corretto .
Esecuzione di istruzioni SQL come comando
// Uses Windows authentication. Replace the Trusted_Connection parameter with
// User Id=...;Password=...; to use SQL Server authentication instead. You may
// want to find the appropriate connection string for your server.
string connectionString = @"Server=myServer\myInstance;Database=myDataBase;Trusted_Connection=True;"
string sql = "INSERT INTO myTable (myDateTimeField, myIntField) " +
"VALUES (@someDateTime, @someInt);";
// Most ADO.NET objects are disposable and, thus, require the using keyword.
using (var connection = new SqlConnection(connectionString))
using (var command = new SqlCommand(sql, connection))
{
// Use parameters instead of string concatenation to add user-supplied
// values to avoid SQL injection and formatting issues. Explicitly supply datatype.
// System.Data.SqlDbType is an enumeration. See Note1
command.Parameters.Add("@someDateTime", SqlDbType.DateTime).Value = myDateTimeVariable;
command.Parameters.Add("@someInt", SqlDbType.Int).Value = myInt32Variable;
// Execute the SQL statement. Use ExecuteScalar and ExecuteReader instead
// for query that return results (or see the more specific examples, once
// those have been added).
connection.Open();
command.ExecuteNonQuery();
}
Nota 1: vedere Enumerazione SqlDbType per la variazione specifica di MSFT SQL Server.
Nota 2: Si prega di consultare Enumerazione MySqlDbType per la variazione specifica di MySQL.
Best practice: esecuzione di istruzioni SQL
public void SaveNewEmployee(Employee newEmployee)
{
// best practice - wrap all database connections in a using block so they are always closed & disposed even in the event of an Exception
// best practice - retrieve the connection string by name from the app.config or web.config (depending on the application type) (note, this requires an assembly reference to System.configuration)
using(SqlConnection con = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MyConnectionName"].ConnectionString))
{
// best practice - use column names in your INSERT statement so you are not dependent on the sql schema column order
// best practice - always use parameters to avoid sql injection attacks and errors if malformed text is used like including a single quote which is the sql equivalent of escaping or starting a string (varchar/nvarchar)
// best practice - give your parameters meaningful names just like you do variables in your code
using(SqlCommand sc = new SqlCommand("INSERT INTO employee (FirstName, LastName, DateOfBirth /*etc*/) VALUES (@firstName, @lastName, @dateOfBirth /*etc*/)", con))
{
// best practice - always specify the database data type of the column you are using
// best practice - check for valid values in your code and/or use a database constraint, if inserting NULL then use System.DbNull.Value
sc.Parameters.Add(new SqlParameter("@firstName", SqlDbType.VarChar, 200){Value = newEmployee.FirstName ?? (object) System.DBNull.Value});
sc.Parameters.Add(new SqlParameter("@lastName", SqlDbType.VarChar, 200){Value = newEmployee.LastName ?? (object) System.DBNull.Value});
// best practice - always use the correct types when specifying your parameters, Value is assigned to a DateTime instance and not a string representation of a Date
sc.Parameters.Add(new SqlParameter("@dateOfBirth", SqlDbType.Date){ Value = newEmployee.DateOfBirth });
// best practice - open your connection as late as possible unless you need to verify that the database connection is valid and wont fail and the proceeding code execution takes a long time (not the case here)
con.Open();
sc.ExecuteNonQuery();
}
// the end of the using block will close and dispose the SqlConnection
// best practice - end the using block as soon as possible to release the database connection
}
}
// supporting class used as parameter for example
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
}
Le migliori pratiche per lavorare con ADO.NET
- La regola generale è di aprire la connessione per un tempo minimo. Chiudere esplicitamente la connessione al termine dell'esecuzione della procedura per ripristinare l'oggetto di connessione sul pool di connessioni. Dimensione massima pool di connessione predefinita = 100. Poiché il pool di connessioni migliora le prestazioni della connessione fisica a SQL Server. Pool di connessioni in SQL Server
- Avvolgi tutte le connessioni del database in un blocco utilizzando in modo che siano sempre chiuse e disposte anche nel caso di un'eccezione. Vedi usando Statement (C # Reference) per ulteriori informazioni sull'uso di istruzioni
- Recupera le stringhe di connessione per nome da app.config o web.config (a seconda del tipo di applicazione)
- Ciò richiede un riferimento all'assembly a
System.configuration
- Vedere Stringhe di connessione e file di configurazione per ulteriori informazioni su come strutturare il file di configurazione
- Ciò richiede un riferimento all'assembly a
- Usa sempre i parametri per i valori in entrata a
- Evita gli attacchi di iniezione sql
- Evitare errori se si utilizza un testo non valido come includere una virgoletta singola che è l'equivalente in sql dell'escape o dell'avvio di una stringa (varchar / nvarchar)
- Lasciando che il provider di database riutilizzi i piani di query (non supportati da tutti i provider di database) aumenta l'efficienza
- Quando si lavora con i parametri
- Il tipo di parametri Sql e la mancata corrispondenza delle dimensioni è una causa comune di errore inserimento / aggiornamento / selezione
- Dai ai tuoi parametri Sql nomi significativi proprio come fai con le variabili nel tuo codice
- Specificare il tipo di dati del database della colonna che si sta utilizzando, questo garantisce che non vengano utilizzati tipi di parametri errati che potrebbero portare a risultati imprevisti
- Convalida i tuoi parametri in entrata prima di passarli al comando (come dice il proverbio, " garbage in, garbage out "). Convalida i valori in entrata il prima possibile nello stack
- Utilizzare i tipi corretti durante l'assegnazione dei valori dei parametri, ad esempio: non assegnare il valore stringa di un DateTime, invece assegnare un'istanza DateTime effettiva al valore del parametro
- Specificare la dimensione dei parametri del tipo di stringa. Ciò è dovuto al fatto che SQL Server può riutilizzare i piani di esecuzione se i parametri corrispondono nel tipo e nella dimensione. Usa -1 per MAX
- Non utilizzare il metodo AddWithValue , il motivo principale è che è molto facile dimenticare di specificare il tipo di parametro o la precisione / la scala quando necessario. Per ulteriori informazioni vedi Come possiamo smettere di usare AddWithValue già?
- Quando si utilizzano connessioni di database
- Apri la connessione il più tardi possibile e chiudila il prima possibile. Questa è una linea guida generale quando si lavora con qualsiasi risorsa esterna
- Non condividere mai istanze di connessione al database (esempio: avere un host singleton un'istanza condivisa di tipo
SqlConnection
). Fai in modo che il codice crei sempre una nuova istanza di connessione al database quando è necessario e quindi richiedi al codice chiamante di eliminarlo e "buttalo via" quando è terminato. La ragione di questo è- La maggior parte dei provider di database ha una sorta di pool di connessioni, quindi la creazione di nuove connessioni gestite è economica
- Elimina eventuali errori futuri se il codice inizia a lavorare con più thread
Utilizzo di interfacce comuni per astrarre le classi specifiche del fornitore
var providerName = "System.Data.SqlClient"; //Oracle.ManagedDataAccess.Client, IBM.Data.DB2
var connectionString = "{your-connection-string}";
//you will probably get the above two values in the ConnectionStringSettings object from .config file
var factory = DbProviderFactories.GetFactory(providerName);
using(var connection = factory.CreateConnection()) { //IDbConnection
connection.ConnectionString = connectionString;
connection.Open();
using(var command = connection.CreateCommand()) { //IDbCommand
command.CommandText = "{query}";
using(var reader = command.ExecuteReader()) { //IDataReader
while(reader.Read()) {
...
}
}
}
}