.NET Framework
ADO.NET
Zoeken…
Invoering
ADO (ActiveX Data Objects) .Net is een tool van Microsoft die via zijn componenten toegang biedt tot gegevensbronnen zoals SQL Server, Oracle en XML. .Net front-end-toepassingen kunnen gegevens ophalen, maken en manipuleren, zodra ze via ADO.Net met de juiste rechten zijn verbonden met een gegevensbron.
ADO.Net biedt een verbindingsloze architectuur. Het is een veilige manier om te communiceren met een database, omdat de verbinding niet gedurende de hele sessie hoeft te worden onderhouden.
Opmerkingen
Een opmerking over het parametreren van SQL's met Parameters.AddWithValue
: AddWithValue
is nooit een goed startpunt. Die methode is gebaseerd op het afleiden van het type gegevens uit wat wordt doorgegeven. Hiermee kunt u in een situatie terechtkomen waarin de conversie voorkomt dat uw zoekopdracht een index gebruikt . Houd er rekening mee dat sommige SQL Server-gegevenstypen, zoals char
/ varchar
(zonder voorafgaande "n") of date
, geen overeenkomstig .NET-gegevenstype hebben. In die gevallen moet in plaats daarvan Add
met het juiste gegevenstype worden gebruikt .
SQL-instructies uitvoeren als een opdracht
// 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();
}
Opmerking 1: Zie SqlDbType Enumeration voor de MSFT SQL Server-specifieke variatie.
Opmerking 2: Zie MySqlDbType Enumeration voor de MySQL-specifieke variatie.
Best Practices - SQL-verklaringen uitvoeren
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; }
}
Best practice voor het werken met ADO.NET
- Vuistregel is om de verbinding voor minimale tijd te openen. Sluit de verbinding expliciet zodra uw procedure is voltooid, keert het verbindingsobject terug naar de verbindingspool. Standaard verbindingspool max. Grootte = 100. Aangezien verbindingspooling de prestaties van de fysieke verbinding met SQL Server verbetert. Verbindingspooling in SQL Server
- Verpak alle databaseverbindingen in een gebruiksblok zodat ze altijd worden afgesloten en verwijderd, zelfs in het geval van een uitzondering. Zie Statement gebruiken (C # Reference) voor meer informatie over het gebruik van statements
- Haal de verbindingsreeksen op naam op via app.config of web.config (afhankelijk van het toepassingstype)
- Dit vereist een assemblageverwijzing naar
System.configuration
- Zie Verbindingsreeksen en configuratiebestanden voor aanvullende informatie over het structureren van uw configuratiebestand
- Dit vereist een assemblageverwijzing naar
- Gebruik altijd parameters voor inkomende waarden tot
- Vermijd sql-injectieaanvallen
- Vermijd fouten als verkeerd opgemaakte tekst wordt gebruikt, zoals het opnemen van een enkele aanhaling die het equivalent in sql is van het ontsnappen of het starten van een tekenreeks (varchar / nvarchar)
- Door de databaseprovider queryplannen te laten hergebruiken (niet door alle databaseproviders ondersteund), wat de efficiëntie verhoogt
- Bij het werken met parameters
- Sql-parameters, type en grootte komen niet overeen, is een veel voorkomende oorzaak van fout bij invoegen / bijwerken / selecteren
- Geef uw SQL-parameters betekenisvolle namen, net zoals u variabelen in uw code doet
- Geef het databasetypetype op van de kolom die u gebruikt, dit zorgt ervoor dat de verkeerde parametertypen niet worden gebruikt, wat kan leiden tot onverwachte resultaten
- Valideer uw inkomende parameters voordat u ze doorgeeft aan de opdracht (zoals het spreekwoord zegt: " garbage in, garbage out "). Valideer inkomende waarden zo vroeg mogelijk in de stapel
- Gebruik de juiste typen bij het toewijzen van uw parameterwaarden, bijvoorbeeld: wijs de tekenreekswaarde van een DateTime niet toe, maar wijs in plaats daarvan een werkelijke DateTime-instantie toe aan de waarde van de parameter
- Specificeer de grootte van string-type parameters. Dit komt omdat SQL Server uitvoeringsplannen opnieuw kan gebruiken als de parameters overeenkomen in type en grootte. Gebruik -1 voor MAX
- Gebruik niet de methode AddWithValue , de belangrijkste reden is dat het heel gemakkelijk is om het parametertype of de precisie / schaal te vergeten wanneer dat nodig is. Zie voor meer informatie Kunnen we AddWithValue al stoppen?
- Bij gebruik van databaseverbindingen
- Open de verbinding zo laat mogelijk en sluit deze zo snel mogelijk. Dit is een algemene richtlijn bij het werken met externe bronnen
- Deel nooit database-verbindingsinstanties (bijvoorbeeld: een singleton host een gedeelde instantie van het type
SqlConnection
). Laat uw code altijd een nieuwe database-verbindingsinstantie maken wanneer dat nodig is en laat de roepcode deze dan weggooien en "gooi het weg" als het klaar is. De reden hiervoor is- De meeste databaseproviders hebben een soort verbindingspooling, dus het maken van nieuwe beheerde verbindingen is goedkoop
- Het elimineert eventuele toekomstige fouten als de code met meerdere threads begint te werken
Het gebruik van gemeenschappelijke interfaces om leverancierspecifieke klassen weg te abstraheren
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()) {
...
}
}
}
}