Szukaj…


Wprowadzenie

ADO (ActiveX Data Objects) .Net to narzędzie firmy Microsoft, które zapewnia dostęp do źródeł danych, takich jak SQL Server, Oracle i XML, za pośrednictwem jego składników. Aplikacje frontowe .Net mogą pobierać, tworzyć i manipulować danymi, gdy zostaną podłączone do źródła danych za pośrednictwem ADO.Net z odpowiednimi uprawnieniami.

ADO.Net zapewnia architekturę bez połączenia. Jest to bezpieczne podejście do interakcji z bazą danych, ponieważ połączenie nie musi być utrzymywane podczas całej sesji.

Uwagi

Uwaga na temat parametryzowania SQL za pomocą Parameters.AddWithValue : AddWithValue nigdy nie jest dobrym punktem wyjścia. Ta metoda polega na wnioskowaniu typu danych na podstawie tego, co jest przekazywane. Dzięki temu może dojść do sytuacji, w której konwersja uniemożliwi wykorzystanie zapytania w indeksie . Zauważ, że niektóre typy danych SQL Server, takie jak char / varchar (bez poprzedzającego „n”) lub date , nie mają odpowiedniego typu danych .NET. W takich przypadkach należy użyć Add z poprawnym typem danych .

Wykonywanie instrukcji SQL jako polecenia

// 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();
}

Uwaga 1: Zobacz wyliczenie SqlDbType dla wersji specyficznej dla MSFT SQL Server.

Uwaga 2: Zobacz wyliczenie MySqlDbType dla odmian specyficznych dla MySQL.

Najlepsze praktyki - wykonywanie instrukcji 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; }
}

Najlepsza praktyka do pracy z ADO.NET

  • Ogólna zasada polega na otwarciu połączenia na minimalny czas. Zamknięcie połączenia jawnie po zakończeniu wykonywania procedury spowoduje powrót obiektu połączenia do puli połączeń. Domyślny maksymalny rozmiar puli połączeń = 100. Ponieważ pula połączeń zwiększa wydajność fizycznego połączenia z programem SQL Server. Pula połączeń w SQL Server
  • Zawiń wszystkie połączenia z bazą danych w blok używający, aby były zawsze zamykane i usuwane nawet w przypadku wyjątku. Aby uzyskać więcej informacji na temat używania instrukcji, zobacz Korzystanie z instrukcji (odniesienie C #)
  • Pobierz parametry połączenia według nazwy z app.config lub web.config (w zależności od typu aplikacji)
  • Zawsze używaj parametrów dla wartości przychodzących do
    • Unikaj ataków typu sql injection
    • Unikaj błędów, jeśli użyjesz zniekształconego tekstu, np. W tym pojedynczego cudzysłowu, który jest odpowiednikiem ucieczki lub rozpoczęcia łańcucha (sqlar / nvarchar)
    • Zezwolenie dostawcy bazy danych na ponowne wykorzystanie planów zapytań (nieobsługiwanych przez wszystkich dostawców baz danych), co zwiększa wydajność
  • Podczas pracy z parametrami
    • Niezgodność typu i rozmiaru parametrów SQL jest częstą przyczyną niepowodzenia wstawiania / aktualizacji / wyboru
    • Nadaj swoim parametrom Sql sensowne nazwy, tak jak robisz zmienne w kodzie
    • Podaj typ danych bazy danych używanej kolumny, dzięki czemu nie zostaną użyte niewłaściwe typy parametrów, co może prowadzić do nieoczekiwanych wyników
    • Sprawdź poprawność parametrów wejściowych przed przekazaniem ich do polecenia (jak mówi przysłowie: „ wyrzuć śmieci, wyrzuć śmieci ”). Sprawdź poprawność wartości przychodzących jak najwcześniej w stosie
    • Podczas przypisywania wartości parametrów użyj poprawnych typów, na przykład: nie przypisuj wartości ciągu DateTime, zamiast tego przypisz rzeczywistą instancję DateTime do wartości parametru
    • Określ rozmiar parametrów typu łańcuchowego. Wynika to z faktu, że SQL Server może ponownie wykorzystywać plany wykonania, jeśli parametry są zgodne pod względem typu i wielkości. Użyj -1 dla MAX
    • Nie używaj metody AddWithValue , ponieważ główną przyczyną jest to, że bardzo łatwo jest zapomnieć o określeniu typu parametru lub precyzji / skali w razie potrzeby. Aby uzyskać dodatkowe informacje, zobacz Czy możemy już przestać używać AddWithValue?
  • Podczas korzystania z połączeń z bazą danych
    • Otwórz połączenie jak najszybciej i zamknij je jak najszybciej. Jest to ogólna wskazówka podczas pracy z dowolnym zasobem zewnętrznym
    • Nigdy nie udostępniaj instancji połączenia z bazą danych (na przykład: host singletonu współużytkowanej instancji typu SqlConnection ). Niech twój kod zawsze tworzy nowe wystąpienie połączenia z bazą danych, gdy jest to potrzebne, a następnie niech kod wywołujący go zutylizuje i „wyrzuci” po zakończeniu. Powodem tego jest
      • Większość dostawców baz danych ma jakąś pulę połączeń, więc tworzenie nowych zarządzanych połączeń jest tanie
      • Eliminuje wszelkie przyszłe błędy, jeśli kod zacznie działać z wieloma wątkami

Korzystanie ze wspólnych interfejsów w celu wyodrębnienia klas specyficznych dla dostawcy

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()) {
                ...
            }
        }
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow