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.
Najnowsze komentarze