Dane są wszędzie, a posiadanie ich I umiejętne wykorzystanie daje przewagę nad konkurencją. Warto więc z nich korzystać w naszych programach. W nauce programowania przychodzi taki moment, że już nie wystarczy zapisywanie pliku txt z informacją. Nawet książka Head First C# zaczyna się od programu wykorzystującego dane. Pracując jako programista nie da się uniknąć aplikacji współpracujących z różnymi bazami danych.
Microsoft wraz z .NET Framework dostarcza świetne narzędzie o nazwie ADO.NET. Jest to bogaty zbiór składników, które umożliwiają komunikację z bazami danych. Pamiętam jak stworzyłem pierwszą swoją aplikację, która połączyła się do bazy i tę radość, jak mi się to udało. Często jest też to aplikacja zaliczeniowa na studiach, więc tym bardziej wpis będzie użyteczny.
Zacznijmy od początku. Stwórzmy sobie klasę, która będzie reprezentowała tabelę w bazie danych:

public class Osoba
{
    public int Id { get; set; }
    public int Imie { get; set; }
    public int Nazwisko { get; set; }
}

Następnie tworzymy klasę odpowiedzialną za manipulację danymi. Aby skorzystać z ADO.NET, należy dodać using do biblioteki System.Data i System.Data.SqlClient. Dodajemy konstruktor, który jako parametry będzie przyjmował adres serwera bazy danych i nazwę bazy danych. Kolejny konstruktor będzie przyjmował dodatkowo login i hasło. Pozwoli to nam tworzyć obiekt połączenia z bazą danych w zależności od tego, czy korzystamy z Windows Authentication, czy SQL Server Authentication. Musimy jeszcze dodać Connection String, który będziemy tworzyli w konstruktorze. Jest to konfiguracja połączenia do bazy danych, dzięki której ADO.NET będzie w stanie nas połączyć.

public class BazaDanych
{
    private string _connectionString;
    public BazaDanych(string adresSerwera, string nazwaBazyDanych)
    {
        _connectionString = $"Data Source={adresSerwera};Initial Catalog={nazwaBazyDanych};Integrated Security=True";
    }

    public BazaDanych(string adresSerwera, string nazwaBazyDanych, string login, string haslo)
    {
        _connectionString = $"Data Source={adresSerwera};Initial Catalog={nazwaBazyDanych};User id={login};Password={haslo}";
    }
}


Teraz musimy napisać metodę, która będzie wykonywała zapytanie w bazie danych i zwracała wynik SELECTa w postaci kolekcji wierszy.
Tworzymy obiekt SqlConnection, który będzie odpowiedzialny za połączenie z bazą danych. Z racji tego, że ma on zaimplementowany interfejs IDisposible i metodę Dispose(), możemy utworzyć go korzystając z using. Jako parametr wejściowy do konstruktora przekazujemy naszego Connection Stringa.
Teraz tworzymy obiekt klasy SqlCommand, który wykona nasze zapytanie na wcześniej utworzonym połączeniu. Nadajemy mu typ tekstowy: CommandType.Text. Do konstruktora przekazujemy nasze zapytanie do bazy i obiekt odpowiedzialny za połączenie z bazą danych.
Następnie tworzymy obiekt DataSet, do którego przekażemy odebrane dane. Ma on bardzo dużo możliwości, ale zazwyczaj wykorzystuje się tylko te podstawowe (polecam poczytać trochę o tym obiekcie w Internecie).
Kolejnym krokiem jest stworzenie obiektu SqlDataAdapter, który odbierze dane z bazy. Korzystając z metody Fill na tym obiekcie i jako parametr podając wcześniej utworzony obiekt DataSet nasze dane zostają pobrane z bazy danych i „wrzucone” do obiektu dataSet.
W ostatnim kroku pobieramy z obiektu dataSet kolekcję tabel pobranych z bazy danych i zwracamy je jako wynik działania naszej metody.

private DataRowCollection ZapytanieSelect(string zapytanie)
{
    DataRowCollection dr;
    string constr = "";
    using (SqlConnection scon = new SqlConnection(constr))
    {
        SqlCommand cmd = new SqlCommand(zapytanie, scon);
        cmd.CommandType = CommandType.Text;
        DataSet dataSet = new DataSet();
        SqlDataAdapter adapter = new SqlDataAdapter(cmd);
        adapter.Fill(dataSet);
        dr = dataSet.Tables[0].Rows;
    }
    return dr;
}

Ostatnim krokiem jest wykorzystanie wyżej stworzonej metody. W tym celu piszemy metodę publiczną, która wykona zapytanie i zwróci nam kolekcję obiektów klasy Osoba.

public IEnumerable PobierzOsoby()
{
    var dane = ZapytanieSelect("SELECT Id, Imie, Nazwisko FROM Osoby");

    foreach(DataRow dr in dane)
    {
        yield return new Osoba
        {
            Id = int.Parse(dr["Id"].ToString()),
            Imie = dr["Imie"].ToString(),
            Nazwisko = dr["Nazwisko"].ToString()
        };
    }
}

W pierwszym kroku korzystamy z przygotowanej metody i pobieramy z bazy danych kolekcję wierszy. Teraz wystarczy zrobić pętlę foreach, która przeiteruje nam naszą kolekcję wierszy. Trzeba pamiętać, aby podać typ danych (DataRow), ponieważ korzystając z var zamiast otrzymywać obiekt DataRow otrzymamy obiekt typu ogólnego Object. W pętli tworzymy nowe obiekty z przedmiotami pobranymi z bazy danych. Można to zrobić na dwa sposoby: 1. dataRow[„NazwaKolumny”] 2. dataRow[numerKolumny] Zalecane jest stosowanie sposobu nr. 1, ponieważ przy dużej ilości pobieranych kolumn łatwo pomylić numer kolumny, dodatkowo zabezpieczamy się przed błędem związanym ze zmianą zapytania np. jeśli podamy nazwy kolumn w innej kolejności, to sposób 1 będzie nadal szukał nazw kolumn, a sposób 2 nie odniesie się do zmian i zamieniając kolejnością siłę z mocą stworzymy obiekt z błędnymi danymi. Wszystkie wyciągnięte dane z DataRow są typu Object, dlatego należy je przekonwertować na odpowiednie typy.
Gdy mamy przygotowaną już metodę, możemy z niej skorzystać i pobrać listę osób:

BazaDanych baza = new BazaDanych("SQLEXPRESS", "PrzykladowaBaza");
List osoby = baza.PobierzOsoby().ToList();

Są tu dwie niewyjaśnione rzeczy: znak $ w konstruktorach i tajemnicze yield return z którym powiązany jest interfejs IEnumerable. Są to jednak bardziej złożone tematy, więc wyjaśnię je w kolejnych wpisach.

Dołącz do newslettera już dziś!
Zero spamu - tylko wartościowe treści!
Musisz już lecieć?
Zostaw swój adres e-mail i dołącz do BEZPŁATNYCH WEBINARÓW dotyczących SQLa!
  • „Jak uczyć się SQLa?” – 4 października
  • „SQL dla testerów” – 12 października