Praca z bazą danych Aby móc korzystać z niniejszego kursu musimy utworzyć bazę danych o nazwie KURSY, tabelę o nazwie UZYTKOWNIK, a w tabeli tej utworzyć następujące kolumny: user_id typu integer/autonumer not null imie typu znakowego o rozmiarze 50 znaków nazwisko typu znakowego o rozmiarze 50 znaków zdjecie typu image/blob/obiektowe Typ danych jest oczywiście zaleŝny od uŝytego serwera, dla MS SQL Serwera definicja bazy, tabeli i kolumn przedstawia się jak poniŝej: Rysunek 1. Projekt tabeli UZYTKOWNIK bazy KURSY W przypadku serwerów MS SQL lub MySQL dodajmy jeszcze uŝytkownika (w tym przykładzie dodany jest uŝytkownik i login tech ), a w przypadku MS SQL równieŝ login tak abyśmy przez tego uŝytkownika mogli łączyć się z bazą danych (szczegóły odnośnie dodawania uŝytkowników w poszczególnych serwerach baz danych proszę doczytać w dokumentacji / literaturze lub w necie). Pragnę tutaj zwrócić uwagę na definicję kolumny user_id, która jest kolumną autoinkrementowaną, czyli numerowaną automatycznie przez system bazy danych. Jeszcze tak pro forma typów danych to w przypadku MySQL będą to odpowiednio typy: BIGINT(20) z opcją autoincrement, VARCHAR(50) i BLOB, a w przypadku Access będą to typy: Autonumer, Tekst(50) i Obiekt Ole. JeŜeli utworzyliśmy juŝ bazę, tabelę i kolumny to teraz trochę teorii na temat łączenia z bazą danych. OtóŜ, aby połączyć się z bazą danych musi być tzw. dostawca, który dostarcza
specjalizowane narzędzia do połączenia się z daną bazą danych. Standardowo środowisko Framework.NET zawiera między innymi dostawców umoŝliwiających łączenie się z MS SQL Serwer (SQLClient), bazą Access (OleDb i ODBC). Dostawca SQLClient jest specjalizowany do połączeń z bazą MS SQL Serwer, natomiast dostawcy OleDb i ODBC są bardziej uniwersalni i pozwalają łączyć się z innymi bazami danych obsługujących / posiadających dany sterownik. W przypadku MySQL najlepiej jest pobrać i zainstalować specjalizowanego dostawcę (MySQLClient) dostępnego na stronie domowej MySQL. Dany sterownik / dostawca zawiera między innymi klasę / obiekt Connection, która za pomocą właściwości ConnectionString łączy się z bazą danych. Tak więc ośmielę się stwierdzić, Ŝe właściwość ConnectionString obiektu Connection jest kluczowym elementem w pracy z bazą danych (bo bez niego i jego prawidłowej postaci nic nie będzie działało, a więc poprawne konstrukcje zapytań SQL tak jak i niepoprawne - nie zadziałają). A skoro tak to teraz omówimy trochę dokładniej tę właściwość. JeŜeli uŝyjemy Wizzarda połączeń do źródeł danych z Visual Studio to utworzona właściwość ConnectionString dla serwera MS SQL będzie miała przykładową postać: Data Source=.\SQLEXPRESS;AttachDbFilename="C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\KURSY.mdf";Persist Security Info=True;User ID=tech;Connect Timeout=30;User Instance=True a dla bazy Access będzie miała przykładową postać: Provider=Microsoft.Jet.OLEDB.4.0;Data Source="C:\Documents and Settings\wicio\Moje dokumenty\moje kursy\kursy.mdb" Jak juŝ pobieŝnie widać, Ŝe pomimo pewnych podobieństw stringi te są róŝne dla róŝnych systemów bazodanowych i prawidłowa definicja tych ciągów jest sporym wyzwaniem nawet dla bardziej doświadczonych programistów. PoniŜej przedstawiam zatem najprostszą konstrukcję działających ConnectionString dla baz danych MS SQL Serwer, Access i MySQL: MS SQL Serwer postać ogólna ConnectionString : server=<nazwa_serwera_lub_jego_ip>\<nazwa_instancji_serwera_sql>,<port>;us er id=<uŝytkownik>;password=<hasło>;database=<nazwa_bazy_danych> gdzie: <nazwa_serwera_lub_jego_ip> to nazwa komputera (lub numer IP tego komputera), na którym zainstalowany jest SQL Serwer (jeŝeli serwer SQL jest zainstalowany na komputerze, na którym będziemy uruchamiali program to moŝna uŝyć nazwy localhost ) <nazwa_instancji_serwera_sql> to nazwa instancji, do której chcemy się podłączyć. Serwer SQL moŝe mieć wiele róŝnych instancji; dla standardowej instalacji będzie to nazwa SQLEXPRESS <port> to numer portu, na którym słucha serwer SQL; standardowo jest to port 1433 <uŝytkownik> to nazwa uŝytkownika posiadającego uprawnienia do bazy danych na serwerze SQL <hasło> to hasło tego uŝytkownika <nazwa_bazy_danych> to nazwa bazy, do której chcemy się podłączyć; kaŝda instancja serwera moŝe zawierać wiele baz danych Przykładowa postać tego łańcucha dla MS SQL Serwera: server=localhost\sqlexpress;user id=tech;password=tech;database=kursy
Access postać ogólna ConnectionString : provider=<nazwa_prowidera>;data Source=<ścieŜka_z_nazwą_pliku_mdb> gdzie: <nazwa_prowidera> to nazwa dostawcy usług połączeniowych < ścieŝka_z_nazwą_pliku_mdb> to nazwa pliku z bazą danych wraz z rozszerzeniem i pełną ścieŝką dostępu Przykładowa postać tego łańcucha dla bazy Access: conn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\Documents and Settings\wicio\Moje dokumenty\moje kursy\kursy.mdb" NaleŜy tutaj zaznaczyć, Ŝe dla połączenia z bazą Access musimy w tym wypadku mieć zainstalowane oprogramowanie MS Jet, które jest standardowo instalowane w przypadku posiadania oprogramowania Office Access. JeŜeli nie mamy zainstalowanego oprogramowania Office Access, a tylko korzystamy z pliku bazy w tym formacie to moŝemy nie mieć zainstalowanego oprogramowania MS Jet i wówczas trzeba je zainstalować. MySQL postać ogólna ConnectionString serwer=<nazwa_serwera_lub_jego_ip>;user id=<uŝytkownik>;password=<hasło>;database=<nazwa_bazy> gdzie: <nazwa_serwera_lub_jego_ip> to nazwa serwera (lub numer IP), na którym zainstalowany jest serwer MySQL <uŝytkownik> to identyfikator uŝytkownika z uprawnieniami do danej bazy <hasło> to hasło tego uŝytkownika <nazwa_bazy> to nazwa bazy danych, do której chcemy się podłączyć Przykładowa postać tego łańcucha dla MySQL: serwer=localhost;user id=admin;password=admin;database=kursy Oczywiście załoŝeniem jest, Ŝe zainstalowany jest odpowiedni dostawca dla MySQL (MySQLClient). To byłoby tyle teorii, a teraz jeszcze zanim przejdziemy do praktyki wprowadźmy do utworzonej tabeli przynajmniej jeden rekord z danymi imie i nazwisko pole zdjecie zostawiamy sobie na następny kurs. Wprowadzenie danych moŝna przeprowadzić za pomocą managera dla MS SQL to SQL Server Management Studio Express dostępny na stronach Microsoftu, dla Access to oczywiście Office Access, a dla MySQL to np. MySQL Administrator dostępny ysql. No to teraz przechodzimy do praktyki. Dokonamy teraz połączenia z bazą, pobrania danych z tabeli UZYTKOWNIK i wyświetlenia tych danych (załóŝmy teoretycznie, Ŝe będą to dane zalogowanego uŝytkownika do bazy teoretycznie, bo nie mamy tu procedury logowania do bazy). Pobrane dane wyświetlimy w pasku stanu okna głównego aplikacji. Na początek zaimportujemy odpowiednią przestrzeń nazw zawierającą obiekty odpowiedniego providera. Dla MS SQL będzie to polecenie: Imports System.Data.SqlClient, dla bazy Acces będzie to polecenie: Imports System.Data.OleDb, a dla bazy MySQL będzie to polecenie: Imports Mysql.Data.MySqlClient. Przy czym dla MySQL musimy najpierw dodać referencje do projektu jak poniŝej (oczywiście przy załoŝeniu, Ŝe zainstalowaliśmy dostawcę dla MySQL):
Rysunek 2. Dodawanie referencji do projektu dla MySQL Aby dodać te referencje musimy na zakładce Solution Explorer zaznaczyć nazwę projektu i wybrać przycisk Properties : Rysunek 3. Wywołanie okna właściwości projektu dla dodania referencji Polecenie Imports umieszczamy na początku kodu przed linią deklarującą klasę: Public Class Glowne. Do pobrania danych uŝyjemy obiektów Connection, Command i DataAdapter właściwych dla danego dostawcy oraz ogólnego obiektu DataSet. W związku z powyŝszym musimy w procedurze Load okna głównego umieścić następujące deklaracje zmiennych: Dim dc As SqlClient.SqlConnection Dim da As SqlClient.SqlDataAdapter Dim cmd As SqlClient.SqlCommand Dim ds As New DataSet
Dim konstr As String Dim komenda As String Oczywiście nazwy dc, da, ds mogą być dowolnie inne, natomiast pod zmienną konstr będziemy przechowywali nasz ConnectionString, a pod zmienną komenda będziemy przechowywali komendę SQL. Dalej w kodzie programu inicjujemy te zmienne i definiujemy ConnectionString : konstr = "serwer=localhost\sqlexpress;user id=tech;password=tech;database=kursy" dc = New SqlClient.SqlConnection(konstr) If dc.state <> ConnectionState.Open Then dc.open() End If da = New SqlClient.SqlDataAdapter() cmd = New SqlClient.SqlCommand Zmienna konstr powinna być zapisana w jednej linii lub, jeŝeli chcemy zapisać w kilku to powinniśmy powiedzieć to kompilatorowi poprzez zapis w następującej postaci: konstr = "serwer=localhost\sqlexpress;" & _ "user id=tech;password=tech;database=kursy" gdzie znak & oznacza łączenie dwóch ciągów w jeden, a znak _ oznacza informację dla kompilatora, Ŝe zapis w linii następnej jest kontynuacją linii bieŝącej. Część kodu zawarta w instrukcji If sprawdza czy połączenie z bazą jest otwarte i jeŝeli nie to je otwiera. Po inicjacji zmiennych konstruujemy zapytanie SQL do bazy i poniewaŝ będzie to instrukcja Select to definiujemy właściwości CommandText i Connection obiektu SqlCommand, wiąŝemy obiekt Command z obiektem DataAdapter poprzez ustawienie właściwości SelectCommand jako, Ŝe polecenie SQL jest typu Select oraz komendę SQL: komenda = "SELECT * FROM UZYTKOWNIK" cmd.commandtext = komenda cmd.connection = dc da.selectcommand = cmd i na koniec pozostaje nam odczyt danych z bazy: Try da.fill(ds, "uzyt") Catch ex As Exception MessageBox.Show(ex.Message, "BŁĄD!!!", MessageBoxButtons.OK, _ MessageBoxIcon.Error, MessageBoxDefaultButton.Button1) End Try PowyŜsza konstrukcja to tzw. przechwytywanie i obsługa błędów i w skrócie polega na tym, Ŝe pomiędzy słowami Try Catch umieszczamy instrukcje, które stanowią potencjalne źródło błędów (polecenia odczytujące dane z bazy mogą generować błędy na skutek np. braku dostępu do bazy z róŝnych przczyn), a pomiędzy Catch End Try umieszczamy kod wykonywany w sytuacji gdy instrukcja wywołała błąd. W naszym przykładzie jako obsługę błędu po prostu wyświetlamy komunikat z treścią błędu w okienku z tytułem BŁĄD!!!, jednym przyciskiem OK. i ikonką błędu w oknie tego komunikatu. JeŜeli chodzi natomiast o komendę: da.fill(ds., uzyt ) to komenda ta powoduje odczyt danych z bazy i zapisanie ich do zmiennej ds będącej obiektem DataSet w tablicy o nazwie uzyt. Obiekt DataSet jest jak gdyby bazą danych mogącą zawierać wiele róŝnych tablic (kaŝda moŝe mieć inną
strukturę) z zawartością wstawioną poprzez odczyt z bazy lub programowo. Mamy juŝ odczytane dane (o ile oczywiście zostały do bazy wprowadzone tabela UZYTKOWNIK zawiera jakieś rekordy danych) więc teraz trzeba by je wyświetlić w pasku stanu. PoniewaŜ pasek stanu zawiera trzy elementy składowe to w jednym umieścimy dane odczytane z bazy, w drugim umieścimy nazwę komputera, a w trzecim nazwę uŝytkownika zalogowanego w systemie Windows. Dane odczytane z bazy mamy w zmiennej ds typu DataSet natomiast pozostałe wartości: nazwę komputera i nazwę uŝytkownika Windows odczytamy ze zmiennych środowiskowych: najpierw zmieniamy nieco definicje zmiennych: Dim komenda, komputer, userwind As String i dopisujemy linie: komputer = System.Environment.MachineName userwind = System.Environment.UserName oraz linie: Me.tsl_kom1.Width = Math.Round(Me.StatusStrip1.Width / 3, 0) Me.tsl_kom2.Width = Math.Round(Me.StatusStrip1.Width / 3, 0) Me.tsl_kom1.Text = "Dane z bazy: " If ds.tables("uzyt").rows.count > 0 Then Me.tsl_kom1.Text = Me.tsl_kom1.Text & _ CStr(ds.Tables("uzyt").Rows(0).Item("nazwisko")) & " " & _ CStr(ds.Tables("uzyt").Rows(0).Item("imie")) End If Me.tsl_kom2.Text = "Nazwa komputera: " & komputer Me.tsl_kom3.Text = "UŜytkownik Windows: " & userwind Pierwsze dwie linie powodują ustawienie długości kaŝdego z dwóch pierwszych elementów paska stanu na 1/3 długości całego paska stanu. Linia trzecia podstawia stały tekst do pierwszego elementu, dalej sprawdzamy czy istnieją jakieś dane odczytane z bazy (to znaczy czy tabela usyt obiektu DataSet zawiera chociaŝ jeden rekord) i jeŝeli tak to dopisuje do tekstu (znak & oznacza dodawanie tekstu) dane z bazy czyli wartość kolumny nazwisko plus znak spacji plus wartość kolumny imie (naleŝałoby tutaj sprawdzić jeszcze czy kolumny te nie zawierają przypadkiem wartości NULL ale tym zajmiemy się w kolejnych kursach zakładamy chwilowo, Ŝe kolumny te zawierają wartości róŝne od NULL). Ostatnie dwie linie to podstawienie odpowiedniego tekstu do kolejnych dwóch elementów paska stanu. Przed zapisem i uruchomieniem programu przejdźmy jeszcze do zakładki Properties dla obiektu StatusStrip, otwórzmy okno dla właściwości Items (Collection) i ustawmy właściwości dla kaŝdego z elementów: BorderSides na All, BorderStyle na Sunken, DisplayStyle na Text oraz dla dwóch pierwszych AutoSize na False, a dla ostatniego Spring na True. Właściwość AutoSize dla dwóch pierwszych ustawiamy na False z tej przyczyny, Ŝe ich długość będziemy ustawiali programowo, czyli ich wymiary nie mogą być ustawiane automatycznie, a dla trzeciego właściwość Spring ustawiamy na True aby ten ostatni wypełnił sobą całą pozostałą przestrzeń (po ustawieniu długości dwóch pierwszych elementów) obiektu StatusStrip. PoniŜszy rysunek prezentuje istotne ustawienia właściwości dwóch pierwszych elementów:
Rysunek 4. Właściwości elementów obiektu StatusStrip Po wprowadzeniu tych zmian zapisujemy i uruchamiamy projekt, w wyniku czego powinniśmy uzyskać poniŝszy efekt:
Rysunek 5. Okno główne aplikacji Cały kod aplikacji powinien wyglądać jak poniŝej: Imports System.Data.SqlClient Public Class Glowne Private Sub Glowne_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim wys, szer As Integer Dim dc As SqlClient.SqlConnection Dim da As SqlClient.SqlDataAdapter Dim cmd As SqlClient.SqlCommand Dim ds As New DataSet Dim konstr As String Dim komenda, komputer, userwind As String wys = Screen.PrimaryScreen.WorkingArea.Height szer = Screen.PrimaryScreen.WorkingArea.Width Me.Height = wys Me.Width = szer konstr = "server=localhost\sqlexpress;" & _ "user id=tech;password=tech;database=kursy" dc = New SqlClient.SqlConnection(konstr) If dc.state <> ConnectionState.Open Then dc.open() End If da = New SqlClient.SqlDataAdapter()
cmd = New SqlClient.SqlCommand komenda = "SELECT * FROM UZYTKOWNIK" cmd.commandtext = komenda cmd.connection = dc da.selectcommand = cmd Try da.fill(ds, "uzyt") Catch ex As Exception MessageBox.Show(ex.Message, "BŁĄD!!!", MessageBoxButtons.OK, _ MessageBoxIcon.Error, MessageBoxDefaultButton.Button1) End Try komputer = System.Environment.MachineName userwind = System.Environment.UserName Me.tsl_kom1.Width = Math.Round(Me.StatusStrip1.Width / 3, 0) Me.tsl_kom2.Width = Math.Round(Me.StatusStrip1.Width / 3, 0) Me.tsl_kom1.Text = "Dane z bazy: " If ds.tables("uzyt").rows.count > 0 Then Me.tsl_kom1.Text = Me.tsl_kom1.Text & _ CStr(ds.Tables("uzyt").Rows(0).Item("nazwisko")) & " " & _ CStr(ds.Tables("uzyt").Rows(0).Item("imie")) End If Me.tsl_kom2.Text = "Nazwa komputera: " & komputer Me.tsl_kom3.Text = "UŜytkownik Windows: " & userwind End Sub Private Sub mi_koniec_click(byval sender As Object, ByVal e As System.EventArgs) Handles mi_koniec.click Application.Exit() End Sub Private Sub tsi_koniec_click(byval sender As Object, ByVal e As System.EventArgs) Handles tsi_koniec.click Me.Close() End Sub End Class To byłoby tyle w tym kursie. Powinniśmy teraz umieć połączyć się z bazą i pozyskać z niej dane jak równieŝ poznaliśmy niektóre komponenty i ich właściwości. W następnym kursie zajmiemy się obsługą danych z tabeli UZYTKOWNIK, a więc wyświetlanie danych, modyfikowanie, dodawanie i usuwanie tych danych ze szczególnym uwzględnieniem zapisu obrazów do bazy i ich wyświetlaniem w programie.