ASP.NET i Web Matrix – część 5
Transkrypt
ASP.NET i Web Matrix – część 5
Obsługa baz danych z użyciem ADO.NET 4. Obsługa baz danych w środowisku Web Matrix Środowisko ASP.NET Web Matrix umożliwia zarówno połączenie z istniejącą bazą danych, jak również utworzenie nowej bazy danych. Założysz teraz na swoim komputerze nową bazę danych o nazwie bank. Będzie ona wykorzystywana już do końca kursu. Warto nadmienić, że w poprzedniej wersji środowiska (0.5) była tylko możliwość dostępu do baz danych MS SQL Server (w okresie, gdy istniała tylko wersja 1.0 .NET Framework). Od wersji 0.6 w środowisku Web Matrix istnieje możliwość obsługi baz danych w formacie MS Access (wiąże się to też z dostępnością wersji 1.1 .NET Framework). Tworzenie bazy danych 1. Pod okienkiem projektu, po prawej stronie ekranu znajdują się trzy zakładki: Workspace, Data oraz Open Windows. W celu rozpoczęcia pracy z bazą danych przełącz się na zakładkę Data. 2. Kliknij w przycisk Add Database Connection znajdujący się na pasku narzędzi Data. 3. Na ekranie pojawi się okno dialogowe Add New Project. Wskaż pozycję Access Database i kliknij w OK. 4. Na ekranie pojawi się teraz okno dialogowe Connect to Database. 5. Kliknij w łącze Create a new database znajdujące się u dołu okna dialogowego Connect to Database. 6. Na ekranie pojawi się okno dialogowe Create New Access Database. W katalogu głównym projektu, obok katalogów ascx, bank, klient, style i temp, stwórz podkatalog dane. Wejdź do środka i w polu nazwy pliku bazy danych wpisz bank.mdb, a następnie kliknij w OK. 7. Środowisko ASP.NET Web Matrix utworzy nową bazę danych bank. W oknie Workspace pojawi się widok drzewa, zawierający węzeł nadrzędny o nazwie bank.mdb (wraz ze ścieżką do katalogu zawierającego plik bazy danych). Rozwiń ten węzeł nadrzędny i kliknij w węzeł o nazwie Tables w widoku drzewa okna Data, a następnie kliknij w przycisk New Database Object znajdujący się na pasku narzędzi Data. 8. Na ekranie pojawi się okno dialogowe Create New Table. 9. W polu Name of the new table wpisz klienci. 10. Stworzona tabela posiada jedną domyślną kolumnę. Zamień ją na klucz główny według wskazówek z punktów 11 i 12. 11. W polu Name, które znajduje się w dolnym obszarze okna, wpisz id. 12. Z listy rozwijanej DataType wybierz pozycję AutoNumber. 1 Obsługa baz danych z użyciem ADO.NET 13. Zmień w polach InPrimaryKey oraz IsUniqueKey wartość na True. 14. Klikając w przycisk New, znajdujący się w lewym górnym rogu okna, możesz dodawać kolejne kolumny. Stwórz w ten sposób kolumny w tabeli klienci, jak pokazano poniżej: Nazwa kolumny (Name) id imie nazwisko adres kod miasto kraj domowy komorkowy email Nazwa właściwości DataType AllowNulls InPrimaryKey IsUniqueKey DataType Size AllowNulls DataType Size AllowNulls DataType Size AllowNulls DataType Size AllowNulls DataType Size AllowNulls DataType Size AllowNulls DataType Size AllowNulls DataType Size AllowNulls DataType Size AllowNulls Wartość właściwości AutoNumber False True True Text 50 False Text 80 False Text 60 False Text 10 False Text 40 False Text 30 False Text 25 True Text 25 True Text 50 True 15. Na dole okna, w którym były tworzone kolumny tabeli znajdują się zakładki Design oraz Data. Możesz teraz dokonać edycji zawartości stworzonej tabeli, wskazując zakładkę Data. Pojawi się pytanie, czy należy zapisać zmiany w schemacie tabeli — należy na nie odpowiedzieć twierdząco. Uwaga: Od momentu, gdy do tabeli zostaną wprowadzone jakiekolwiek dane, nie można już zmieniać jej schematu. Dlatego przed stworzeniem początkowych danych upewnij się, czy kolumny tabeli są zgodne z powyższą specyfikacją. 16. Do tabeli klienci wpisz przynajmniej cztery nowe wiersze danych. Pamiętaj, że musisz podać wartości dla wszystkich kolumn, które mają właściwość AllowNulls równą False. Uwaga: Aby zapamiętać zmieniony wiersz w bazie danych, naciśnij klawisz Enter lub zaznacz inny wiersz w siatce danych. Uwaga: Kolumna id ma domyślnie ustawione właściwości IdentitySeed oraz IdentityIncremenet (automatyczne numerowanie od 1 z krokiem 1). Baza danych 2 Obsługa baz danych z użyciem ADO.NET automatycznie wylicza i przypisuje nową wartość polu typu AutoNumber w momencie zapisywania wiersza w bazie danych. Uwaga: Siatka danych wyświetlana w oknie Data umożliwia tylko odczytywanie wartości pól typu AutoNumber. Uwaga: Aby wyświetlić widok definicji tabeli, w trakcie edycji kliknij w zakładkę Design, znajdującą się u dołu okna dialogowego. Nie możesz zmienić definicji tabeli, jeśli znajdują się w niej jakiekolwiek dane. 17. Możesz zamknąć okno edycji tabeli. Dane w bazie zostaną automatycznie zapisane. Najprostszy odczyt danych z bazy Jeśli chodzi tylko o szybkie wyświetlenie zawartości całej tabeli, to w środowisku Web Matrix jest to wyjątkowo proste. Wystarczy przeciągnąć wybraną tabelę na stronę, aby automatycznie pojawiły się tam dwie kontrolki umożliwiające przeglądanie zawartości tabeli. Należy jednak podkreślić, że są to kontrolki dostarczane ze środowiskiem Web Matrix. Ich zadaniem jest uproszczenie budowy stron w tym środowisku, nie są to natomiast kontrolki standardowe ASP.NET (które będą omówione już niebawem). Rysunek 4. Wygląd strony po przeciągnięciu na nią tabeli klienci Jedna ogólna uwaga jest następująca — Web Matrix niezbyt uważnie obsługuje dyrektywy plików włączanych, umieszczone w kodzie HTML. Warto więc co jakiś czas zaglądać, czy ostatnio dokonane zmiany nie spowodowały jakichś katastrofalnych zmian w budowie strony. Dotyczy to zwłaszcza wstawiania lub usuwania elementów z początku, a zwłaszcza z samego końca strony (często znika lub zostaje niepoprawnie umieszczone odwołanie do pliku Footer.txt). 3 Obsługa baz danych z użyciem ADO.NET W celu podglądu tabeli klienci w przeglądarce wykonaj następujące czynności: 18. Otwórz plik Default.aspx z podkatalogu bank. 19. Kliknij w zakładkę Data znajdującą się pod okienkiem projektu po prawej stronie ekranu. 20. Upewnij się, czy masz otwarte połączenie do odpowiedniej bazy danych. 21. Znajdź węzeł opisujący tabelę klienci. 22. Przeciągnij tabelę klienci z okienka Data na stronę Default.aspx, przed napis treść (jest to bezpieczne rozwiązanie). Pojawią się dwie kontrolki: niewizualna — bez reprezentacji w kodzie HTML — AccessDataSourceControl oraz MxDataGrid. Teraz dopiero usuń napis treść. Możesz również sprawdzić na zakładce HTML, czy wszystko jest w porządku. 23. Zapisz dokonane zmiany i przejdź do okna przeglądarki (o ile masz już uruchomioną aplikację). Wybierz z menu w kategorii Obsługa polecenie Administracja. 24. Sprawdź działanie strony. Zauważ, że domyślnie można klikać w nagłówki kolumn, żeby zmieniać sposób sortowania danych. 25. Zauważ, że zmieniając w środowisku Web Matrix właściwości kontrolki MxDataGrid, takie jak PageSize, AllowPaging, AllowSorting, GridLines i inne, jesteś w stanie wpływać na sposób wyświetlania tabeli na stronie. 26. Zauważ, że widoczne są wszystkie kolumny tabeli (co czasem nie jest pożądane), oraz że nie zawsze mają one poprawne polskie nazwy (np. id zamiast nr, imie zamiast imię, komorkowy zamiast tel. komórkowy itp.). Ten problem zostanie rozwiązany przy samodzielnej obsłudze standardowej kontrolki DataGrid ASP.NET. Można również ustawić właściwość AutoGenerateFields kontrolki MxDataGrid na False i wskazać, jakie kolumny mają być widoczne, zmieniając jej kolekcję Fields. Odłączanie się od bazy danych 27. Kliknij w zakładkę Data znajdującą się pod okienkiem projektu po prawej stronie ekranu. 28. W widoku drzewa w oknie Data kliknij w nadrzędny węzeł bazy bank.mdb. 29. Kliknij w przycisk Close Database Connection znajdujący się na pasku narzędzi Data. Uwaga: Dopóki nie zostanie zaznaczony nadrzędny węzeł serwera w widoku drzewa w oknie Data, przycisk Close Database Connection pozostaje nieaktywny. Konfiguracja źródła danych Kontrolka AccessDataSourceControl posiada tylko trzy właściwości. Dwiema najważniejszymi są ConnectionString oraz SelectCommand. Pierwsza określa źródło danych, w tym wykorzystywany sterownik oraz pełną ścieżkę do pliku bazy .mdb. Druga 4 Obsługa baz danych z użyciem ADO.NET określa polecenie SQL służące do odczytu danych. Wstawienie takiej kontrolki na stronę powoduje podstawowy kłopot konfiguracyjny: ścieżka do pliku bazy danych jest za każdym razem wpisana bezpośrednio w kontrolkę. O ile czasem konieczne jest to, aby pewne mechanizmy środowiska Web Matrix działały, stanowi to kłopot przy praktycznym wdrażaniu aplikacji. Zmiana położenia pliku bazy danych powoduje bowiem konieczność zmiany w kodzie źródłowym stron .aspx. Często stosowanym i zalecanym rozwiązaniem jest uniezależnienie gotowej aplikacji od położenia bazy danych, którą wykorzystuje. W ten sposób administrator jest w stanie zmienić konfigurację aplikacji bez zmiany jej kodu źródłowego. Na szczęście okazuje się, że twórcy ASP.NET pomyśleli także i o tym. Istnieje bowiem możliwość umieszczenia własnych informacji konfiguracyjnych w pliku konfiguracyjnym aplikacji web.config. Przeniesiesz teraz informacje o sposobie łączenia się z bazą danych z pliku bank/Default.aspx do pliku web.config. W tym celu wykonaj poniższe czynności: 30. Otwórz plik Default.aspx z podkatalogu bank projektu (jeśli masz ten plik otwarty, to przejdź do niego). 31. Kliknij w kontrolkę AccessDataSourceControl i zaznacz cały napis będący wartością jej właściwości ConnectionString. Zaznaczony napis wytnij do schowka. 32. Otwórz plik web.config z katalogu głównego projektu. Był on tworzony na końcu modułu 4. Jeśli jeszcze nie masz tego pliku, to stwórz nowy plik konfiguracyjny aplikacji poleceniem File New File, wskazując Web.Config w sekcji General. Zapisz go w katalogu głównym projektu pod wymaganą nazwą web.config. 33. Znajdź umieszczoną w komentarzu nieaktywną sekcję <appSettings>. Zamień w kluczu "connectionstring" wartość atrybutu value na napis umieszczony w schowku (czyli poprzednią wartość właściwości ConnectionString kontrolki). Następnie przenieś koniec komentarza przed samą sekcję <appSettings>, podobnie jak w poniższym przykładzie: Przykład 11. Dodanie klucza konfiguracyjnego, opisującego sposób łączenia się z bazą danych <?xml version="1.0" encoding="UTF-8" ?> <configuration> <!-The <appSettings> section is used to configure 5 Obsługa baz danych z użyciem ADO.NET application-specific configuration settings. These can be fetched from within apps by calling the "ConfigurationSettings.AppSettings(key)" method: --> <appSettings> <add key="connectionstring" value="Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4; Data Source=C:\ASP.NET\MojBank\dane\bank.mdb"/> </appSettings> <system.web> ... 34. Zapisz zmiany dokonane w pliku web.config. 35. Wróć do pliku Default.aspx i stwórz dla strony (Page) obsługę zdarzenia Load. Wpisz kod ustawiający łańcuch połączenia z bazą danych przy ładowaniu strony: Przykład 12. Ustawianie właściwości ConnectionString przy ładowaniu strony void Page_Load(object sender, EventArgs e) { AccessDataSourceControl1.ConnectionString = ConfigurationSettings.AppSettings["connectionstring"]; } 36. Zapisz dokonane zmiany i sprawdź, czy wybranie z menu w kategorii Obsługa polecenia Administracja nadal wyświetla tabelę klientów. Konfiguracja taka, tzn. zapisana w pliku web.config w postaci pary klucz–wartość, będzie wykorzystywana już do końca kursu. Pozwala to na łatwe przeniesienie pliku bazy danych do innego katalogu i aktualizację informacji o tym w jednym miejscu (znów mamy zastosowanie reguły DRY). Powyższa zmiana konfiguracji źródła danych (kontrolki AccessDataCourceControl) powoduje jednak, że pewne opcje środowiska Web Matrix stają się niedostępne — jak np. lista kolumn tabeli podczas edycji strony w trybie wizualnym. Warto zapamiętać więc, żeby takie zmiany — jako część konfiguracyjna aplikacji — wprowadzać dopiero po 6 Obsługa baz danych z użyciem ADO.NET sprawdzeniu poprawności działania strony. W przeciwnym przypadku może okazać się konieczne przywrócenie niektórym źródłom danych informacji o bazie danych, z których mają korzystać. 7 Obsługa baz danych z użyciem ADO.NET 5. Kontrolki powiązane z danymi Podgląd jednej tabeli, jakkolwiek potrzebny, to nie wszystko, co można osiągnąć korzystając z ADO.NET. Kontrolki ASP.NET mogą być wiązane z danymi pobieranymi z wybranego źródła danych. Wystarczy więc powiązać kontrolkę z wybraną źródłem danych (ustawiając właściwość DataSource) oraz wskazać kolumnę (właściwości DataTextField i/lub DataValueField), aby zobaczyć dane tam się znajdujące. Kontrolki, które mogą przechować więcej niż jedną wartość mają te właściwości. Z kontrolek standardowych są to np. DropDownList, RadioButtonList, ListBox, DataGrid. Wymóg przechowywania wielu wartości ma swoją przyczynę — polecenie SQL SELECT może przecież zwrócić całą listę wyników. Dla dowolnej właściwości pozostałych kontrolek można poza tym ustawić powiązania z danymi, modyfikując kolekcję (DataBindings). W ten sposób wartość dowolnej właściwości kontrolki może być pobierana ze źródła danych. Sztuką jest tylko zbudowanie odpowiedniego wyrażenia wiążącego. Po ustaleniu, co z czym ma być związane, wystarczy zażądać powiązania kontrolek z danymi — zawsze, gdy trzeba pokazać zmiany w danych. Powiązanie dla każdej potrzebnej kontrolki odbywa się przez wywołanie jej metody DataBind(). Wiązanie kontrolek najczęściej odbywa się wewnątrz obsługi zdarzenia Load strony (dla wyświetlenia wartości początkowych) lub w metodach obsługi innych zdarzeń (gdy po zmianie danych trzeba zaktualizować interfejs użytkownika). Warto zauważyć, że jeśli kontrolka jest zawsze wiązana w obsłudze zdarzenia Load strony, bez sprawdzania warunkiem if (!IsPostBack), czy jest to pierwsze żądanie strony, to wszelkie zmiany dokonane przez użytkownika w takiej kontrolce są gubione. Czasem jest to pożądane, ale czasem nie. Istnieje też możliwość wywołania metody DataBind() dla samej strony — wtedy wywołania metod DataBind() dla pozostałych kontrolek na niej zawartych wykonywane są automatycznie. Mogą jednak być przy tym zgubione zmiany w powiązanych kontrolkach (np. wybrana pozycja z listy). Rozbudujesz teraz stronę Obsługa klienta tak, żeby można było przeglądać informacje o wybranym kliencie banku. W tym celu wykonaj poniższe czynności: 8 Obsługa baz danych z użyciem ADO.NET 1. Otwórz plik Kasa.aspx z podkatalogu bank. 2. Wstaw na stronę z okienka Toolbox, z zakładki Web Controls kontrolkę AccessDataSourceControl — przed napisem treść. Zmień nazwę tej kontrolki (jej właściwość (ID)) na Select_id_klienci. 3. Zamień napis treść na Numer klienta: oraz wstaw za nim kontrolkę listy rozwijanej DropDownList. Zmień nazwę tej kontrolki (właściwość (ID)) na DdLstId. 4. Wstaw za listą rozwijaną przycisk i zmień jego nazwę (ID) na BtnOdswiez. 5. Ustaw właściwości kontrolek zgodnie z poniższą tabelą: Typ kontrolki AccessDataSourceControl DropDownList Button Nazwa właściwości (ID) SelectCommand (ID) DataSource DataTextField DataValueField AutoPostBack (ID) Text Wartość właściwości Select_id_klienci SELECT id FROM [klienci] DdLstId Select_id_klienci id id True BtnOdswiez Odśwież 6. Dodaj dla strony (Page) obsługę zdarzenia Load. Wpisz pomocniczą metodę ustawiającą dla źródła danych właściwość ConnectionString na odczytaną z pliku web.config oraz kod korzystający z tej metody: Przykład 13. Konfiguracja źródła danych i wiązanie kontrolek z danymi przy pierwszym ładowaniu strony void BindControlsToData() { Select_id_klienci.ConnectionString = ConfigurationSettings.AppSettings["connectionstring"]; DdLstId.DataBind(); } void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { BindControlsToData(); } } 7. Włącz stronę Obsługa klienta i sprawdź, czy po połączeniu się z bazą danych w liście rozwijanej pojawiły się identyfikatory wierszy z tabeli klienci. 9 Obsługa baz danych z użyciem ADO.NET 8. Dodaj dla przycisku Odśwież obsługę zdarzenia Click. Wpisz kod powodujący odświeżenie zawartości listy rozwijanej z numerami klientów: Przykład 14. Ponowne wiązanie kontrolki z danymi void BtnOdswiez_Click(object sender, EventArgs e) { BindControlsToData(); } 9. Sprawdź działanie przycisku Odśwież przez dodanie w środowisku Web Matrix nowego wiersza w tabeli klienci, a następnie wciśnięcie tego przycisku w oknie przeglądarki. Lista powinna zawierać numer nowo dodanego klienta. 5.1. Korzystanie z modułów generacji kodu Wyświetlanie numerów klientów to podstawowy element potwierdzający skuteczność działania. Teraz dodasz kontrolki wyświetlające informacje o kliencie oraz obsługę zdarzeń. Skorzystasz tu z modułu generacji kodu SELECT Data Code Wizard. Stworzy on kod z obsługą komponentów ADO.NET, dzięki któremu będzie można pobierać dane z bazy. W tym celu wykonaj poniższe czynności: 10. Otwórz zakładkę Data w oknie projektu i połącz się z utworzoną wcześniej bazą bank.mdb. 11. Przełącz się na zakładkę Design i wstaw napisy oraz kontrolki TextBox jak poniżej: Rysunek 5. Wygląd strony do odczytu podstawowych informacji o klientach 10 Obsługa baz danych z użyciem ADO.NET 12. Ustaw właściwości kontrolek zgodnie z poniższą tabelą: Typ kontrolki TextBox TextBox Nazwa właściwości (ID) ReadOnly (ID) ReadOnly Wartość właściwości TxtImie True TxtNazwisko True 13. Przełącz się na zakładkę Code i zauważ, jak zmieniła się zawartość okienka Toolbox. Jest tam wyświetlona zakładka Code Wizards z pięcioma kreatorami — modułami generowania kodu. 14. Przeciągnij generator kodu SELECT Data Method do okna Code, poniżej metody BtnOdswiez_Click. Na ekranie pojawi się okno dialogowe Select a Database Connection. 15. W polu wyboru Select a database wybierz połączenie z bazą danych bank.mdb (jeśli jest otwarta) lub wskaż pozycję <New Database Connection> i wciśnij przycisk Create..., aby stworzyć nowe połączenie do tej bazy. 16. Kliknij w przycisk Next. 17. Na ekranie pojawi się okno dialogowe Construct a SELECT query, prezentujące pierwszy ekran kreatora generacji kodu. 18. Z listy Tables wybierz element klienci. 19. Zaznacz pole wyboru znajdujące się obok pozycji imie oraz nazwisko na liście Columns. W ten sposób dokonasz wyboru kolumn odczytywanych z tabeli. 20. Kliknij w przycisk WHERE. 21. Na ekranie pojawi się okno dialogowe WHERE Clause Builder. 22. Z listy Column wybierz element id. Uwaga: Opcja ta określa argumenty znajdujące się na lewo od klauzuli WHERE. 23. Kliknij w przycisk radiowy Filter, a w polu filtru wpisz @id (są to wartości domyślne). Uwaga: Opcja ta określa argumenty znajdujące się na prawo od klauzuli WHERE. Wartość ta zostanie przekazana jako parametr przy wykorzystaniu powstałego kodu. 24. Kliknij w przycisk OK. 25. Powrócisz teraz do kreatora SELECT Data Code Wizard i etapu Construct a SELECT Query. Zauważ, jak zmieniła się zawartość pól WHERE clause oraz Preview. 26. Kliknij w przycisk Next. 27. Na ekranie pojawi się drugie okno dialogowe kreatora SELECT Data Code Wizard, Query Preview. 28. Kliknij w przycisk Test Query. 29. W polu [klienci].[id] = wpisz 1. 30. Kliknij w przycisk OK. 11 Obsługa baz danych z użyciem ADO.NET 31. Na ekranie zobaczysz okno dialogowe Query Preview, w którym zostanie wyświetlony wiersz tabeli klienci, odpowiadający warunkowi id = 1. 32. Kliknij w przycisk Next. 33. Na ekranie pojawi się trzecie okno dialogowe kreatora SELECT Data Code Wizard, Name Method. W polu nazwy metody wpisz DaneKlienta. 34. Kliknij w przycisk radiowy DataSet (jest to wartość domyślna). 35. Kliknij w przycisk Finish. 36. Okno kreatora zniknie, a w widoku Code pojawi się metoda DaneKlienta. Jako parametr wejściowy przyjmuje ona wartość liczbową id, zaś w wyniku działania zwraca zestaw danych DataSet. Zwrócony zestaw danych zawiera dane dotyczące klienta o identyfikatorze id, pobrane z użyciem mechanizmu ADO.NET. 37. Wygenerowany w ten sposób kod ma wpisaną pełną ścieżkę dostępu do pliku bank.mdb, czyli na pewno będzie poprawnie działać na komputerze, przy którym pracujesz. Znasz już jednak rozwiązanie tego problemu — wystarczy nieco poprawić początek metody DaneKlienta, aby ścieżka do bazy była odczytywana z pliku web.config: Przykład 15. Odczyt klucza konfiguracyjnego, opisującego sposób łączenia się z bazą danych System.Data.DataSet DaneKlienta(int id) { string connectionString = ConfigurationSettings.AppSettings["connectionstring"]; System.Data.IDbConnection dbConnection = new System.Data.OleDb.OleDbConnection(connectionString); string queryString = "SELECT [klienci].[imie], " + "[klienci].[nazwisko] FROM [klienci] WHERE " + "([klienci].[id] = @id)"; ... 38. Przejdź teraz do zakładki Design i stwórz dla kontrolki DdLstId obsługę zdarzenia SelectedIndexChanged. Kluczową sprawą jest tutaj ustawiona na True właściwość AutoPostBack kontrolki. Dzięki temu można reagować na zmianę wybranego numeru klienta i zgodnie z nim aktualizować zawartość pozostałych kontrolek. 39. Wpisz kod realizujący zmiany w kontrolkach, jak poniżej: Przykład 16. Odczyt i wyświetlenie informacji o wybranym kliencie void DdLstId_SelectedIndexChanged(object sender, EventArgs e) { 12 Obsługa baz danych z użyciem ADO.NET try { // Odczytanie wartości kolumny id wybranego klienta string numer = DdLstId.SelectedItem.Value; int id = Convert.ToInt32(numer); // Odczytanie wiersza danych z bazy System.Data.DataSet ds = DaneKlienta(id); // Wyświetlenie informacji o kliencie TxtImie.Text = ds.Tables[0].Rows[0]["imie"].ToString(); TxtNazwisko.Text = ds.Tables[0].Rows[0]["nazwisko"].ToString(); } catch (Exception ex) { // Zabezpieczenie przed błędem, gdy brak id w bazie TxtImie.Text = TxtNazwisko.Text = ""; } } 40. Po zapisaniu zmian i uruchomieniu strony zauważ, że przy pierwszym wejściu na tę stronę wypełniana jest lista numerów klientów, ale brakuje danych pierwszego zaznaczonego klienta. Dodaj więc w pomocniczej metodzie BindControlsToData, wywoływanej przy pierwszym ładowaniu oraz odświeżaniu strony, żądanie aktualizacji jej zawartości: Przykład 17. Aktualizacja informacji o kliencie przy pierwszym ładowaniu strony void BindControlsToData() { Select_id_klienci.ConnectionString = ConfigurationSettings.AppSettings["connectionstring"]; DdLstId.DataBind(); // Wymuszona aktualizacja zawartości kontrolek DdLstId_SelectedIndexChanged(this, null); } 41. Wróć do przeglądarki i w menu nawigacyjnym wskaż inną stronę, a następnie znów stronę Obsługa klienta. Sprawdź, czy dane pojawiają się po pierwszym wejściu na stronę. 5.2. Inne sposoby odczytu danych 13 Obsługa baz danych z użyciem ADO.NET Jak już było wspomniane, uzyskany w powyższy sposób zbiór danych DataSet jest najbardziej elastycznym sposobem obsługi danych. Natomiast obiekt DataReader ma prostszą budowę i pozwala na jednokrotny odczyt uzyskanych danych — tylko w przód. Dodasz teraz możliwość wyświetlenia adresu klienta przez obiekt DataReader, a następnie zobaczysz, jak powiązać z danymi kontrolki wyświetlające adres e-mail oraz numery telefonów klienta, przez wyrażenia wiążące. W tym celu wykonaj poniższe czynności: 42. Wstaw na stronę przycisk Button Szczegóły >> za nazwiskiem klienta. 43. Poniżej wstaw kontrolkę Panel i umieść na niej kontrolki jak na rysunku: Rysunek 6. Strona z możliwością wyświetlania szczegółów dotyczących klienta 14 Obsługa baz danych z użyciem ADO.NET 44. Ustaw właściwości kontrolek zgodnie z poniższą tabelą: Typ kontrolki Panel <TABLE> TextBox TextBox TextBox TextBox TextBox TextBox HyperLink Nazwa właściwości (ID) Width border height width (ID) ReadOnly (ID) ReadOnly (ID) ReadOnly (ID) ReadOnly (ID) ReadOnly (ID) ReadOnly (ID) Text Wartość właściwości PanelSzczegoly 580px 1 140px 570px TxtAdres True TxtKod True TxtMiasto True TxtKraj True TxtDomowy True TxtKomorkowy True LnkEmail (brak) 45. Przełącz się na zakładkę Code i przeciągnij ponownie generator kodu SELECT Data Method do okna Code, poniżej metody DdLstId_SelectedIndexChanged. Na ekranie pojawi się okno dialogowe Select a Database Connection. 46. Aktywne jest ostatnie, właściwe połączenie. Kliknij w przycisk Next. 47. W liście kolumn zaznacz: adres, kod, miasto i kraj. 48. Kliknij w przycisk WHERE. 49. Kliknij w przycisk OK. 50. Kliknij w przycisk Next. 51. Jeśli chcesz, możesz sprawdzić budowę zapytania klikając w przycisk Test Query. 52. Kliknij w przycisk Next. 53. W polu nazwy metody wpisz AdresKlienta. 54. Kliknij tym razem (to ważne!) w przycisk radiowy DataReader. 55. Kliknij w przycisk Finish. 56. Okno kreatora zniknie, a w widoku Code pojawi się metoda AdresKlienta. Jako parametr wejściowy przyjmuje ona wartość liczbową id, lecz w wyniku działania zwraca obiekt DataReader. 57. Wygenerowany w ten sposób kod ma wpisaną pełną ścieżkę dostępu do pliku bank.mdb. Popraw początek metody AdresKlienta, aby ścieżka do bazy była odczytywana z pliku web.config: Przykład 18. Odczyt z bazy danych adresu wybranego klienta 15 Obsługa baz danych z użyciem ADO.NET System.Data.IDataReader AdresKlienta(int id) { string connectionString = ConfigurationSettings.AppSettings["connectionstring"]; System.Data.IDbConnection dbConnection = new System.Data.OleDb.OleDbConnection(connectionString); string queryString = "SELECT [klienci].[adres], " + "[klienci].[kod], [klienci].[miasto], [klienci].[kraj] " + "FROM [klienci] WHERE ([klienci].[id] = @id)"; ... 58. Powyższa metoda zwraca obiekt posiadający interfejs o nazwie IDataReader. Jednak, żeby móc odczytać z uzyskanego obiektu dane, trzeba będzie odzyskać jego właściwy typ, wykonując rzutowanie do konkretnej klasy. Z analizy treści metody AdresKlienta wynika, że w tym przypadku będzie to System.Data.OleDb.OleDbDataReader. Już za chwilę wykorzystasz ten fakt. 59. Dodaj w metodzie Page_Load ustawienie początkowego stanu panelu jako niewidoczny: Przykład 19. Ukrycie panelu ze szczegółami przy pierwszym ładowaniu strony void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { PanelSzczegoly.Visible = false; BindControlsToData(); } } 60. Przejdź teraz do zakładki Design i stwórz dla przycisku BtnSzczegoly obsługę zdarzenia Click. Wpisz kod poniższych metod, które przełączają widoczność panelu ze szczegółami klienta oraz aktualizują zawarte w nim kontrolki: Przykład 20. Odczyt z bazy adresu wybranego klienta void BtnSzczegoly_Click(object sender, EventArgs e) { PanelSzczegoly.Visible = !PanelSzczegoly.Visible; if (PanelSzczegoly.Visible) { 16 Obsługa baz danych z użyciem ADO.NET BtnSzczegoly.Text = "<< Ukryj"; try { // Wywołanie z odczytanym numerem klienta PokazAdresKlienta(Convert.ToInt32(DdLstId.SelectedItem.Value)); } catch (Exception ex) { // Na wypadek błędu - usunięcie danych PokazAdresKlienta(0); } } else { BtnSzczegoly.Text = "Szczegóły >>"; } } void PokazAdresKlienta(int id) { try { // Odczytanie adresu z bazy danych, odzyskanie typu obiektu System.Data.OleDb.OleDbDataReader dr = (System.Data.OleDb.OleDbDataReader) AdresKlienta(id); // Sprawdzenie, czy ostrzymaliśmy dane if (dr.HasRows && dr.Read()) { // Wyświetlenie adresu klienta TxtAdres.Text = dr["adres"].ToString(); TxtKod.Text = dr["kod"].ToString(); TxtMiasto.Text = dr["miasto"].ToString(); TxtKraj.Text = dr["kraj"].ToString(); } else { // Żądanie usunięcia danych id = 0; } } catch (Exception ex) { // Żądanie usunięcia danych id = 0; } if (id == 0) { // Usunięcie danych 17 Obsługa baz danych z użyciem ADO.NET TxtAdres.Text = TxtKod.Text = TxtMiasto.Text = TxtKraj.Text = ""; } } 61. Takie rozwiązanie działa świetnie dla aktualnego klienta. Jeśli natomiast numer klienta zostanie zmieniony, w czasie gdy otwarte są szczegóły, dane te pozostają bez zmian. Dlatego trzeba jeszcze rozbudować metodę obsługi zdarzenia SelectedIndexChanged: Przykład 21. Wyświetlanie szczegółów klienta przy zmianach numeru klienta void DdLstId_SelectedIndexChanged(object sender, EventArgs e) { try { // Odczytanie wartości kolumny id wybranego klienta string numer = DdLstId.SelectedItem.Value; int id = Convert.ToInt32(numer); // Odczytanie wiersza danych z bazy System.Data.DataSet ds = DaneKlienta(id); // Wyświetlenie informacji o kliencie TxtImie.Text = ds.Tables[0].Rows[0]["imie"].ToString(); TxtNazwisko.Text = ds.Tables[0].Rows[0]["nazwisko"].ToString(); if (PanelSzczegoly.Visible) { // Wyświetlenie adresu klienta PokazAdresKlienta(id); } } catch (Exception ex) { // Zabezpieczenie przed błędem, gdy brak id w bazie TxtImie.Text = ""; TxtNazwisko.Text = ""; } } 5.3. Wiązanie kontrolek z danymi Trzecim sposobem wyświetlania danych jest użycie wiązania kontrolek z danymi. Na początku modułu podany był przykład, gdzie wartość właściwości kontrolki była określona jako wartość wskazanej właściwości innej kontrolki. W przypadku odczytu danych z bazy 18 Obsługa baz danych z użyciem ADO.NET sytuacja jest trochę inna — aby skorzystać z wiązania danych muszą istnieć globalnie dostępne symbole, które będą użyte przy budowie wyrażeń wiążących. Następnie przed wywołaniem metod DataBind() trzeba spowodować, żeby wspomniane symbole zawierały dane przeznaczone do wyświetlenia. Zrobisz teraz ostatnie zmiany na stronie Kasa.aspx, tak aby były wyświetlane opcjonalne szczegóły dotyczące klienta: numery telefonów i adres e-mail. Wykorzystany zostanie do tego mechanizm wiązania kontrolek z danymi. W tym celu wykonaj poniższe czynności: 1. Przełącz się na zakładkę Code i przeciągnij generator kodu SELECT Data Method do okna Code, poniżej metody PokazAdresKlienta. Na ekranie pojawi się okno dialogowe Select a Database Connection. 2. Aktywne jest ostatnie, właściwe połączenie. Kliknij w przycisk Next. 3. W liście kolumn zaznacz: domowy, komorkowy i email. 4. Kliknij w przycisk WHERE. 5. Kliknij w przycisk OK. 6. Kliknij w przycisk Next. 7. Jeśli chcesz, możesz sprawdzić budowę zapytania klikając w przycisk Test Query. 8. Kliknij w przycisk Next. 9. W polu nazwy metody wpisz SzczegolyKlienta. 10. Kliknij (to ważne!) w przycisk radiowy DataReader. 11. Kliknij w przycisk Finish. 12. Okno kreatora zniknie, a w widoku Code pojawi się metoda SzczegolyKlienta. Jako parametr wejściowy przyjmuje ona wartość liczbową id, zaś w wyniku działania zwraca obiekt DataReader. 13. Wygenerowany w ten sposób kod ma wpisaną pełną ścieżkę dostępu do pliku bank.mdb. Popraw początek metody SzczegolyKlienta, aby ścieżka do bazy była odczytywana z pliku web.config: Przykład 22. Odczyt z bazy danych szczegółów wybranego klienta System.Data.IDataReader SzczegolyKlienta(int id) { string connectionString = ConfigurationSettings.AppSettings["connectionstring"]; System.Data.IDbConnection dbConnection = new 19 Obsługa baz danych z użyciem ADO.NET System.Data.OleDb.OleDbConnection(connectionString); string queryString = "SELECT [klienci].[domowy], " + "[klienci].[komorkowy], [klienci].[email] " + "FROM [klienci] WHERE ([klienci].[id] = @id)"; ... 14. Wpisz za wygenerowaną metodą SzczegolyKlienta deklarację globalnej zmiennej SzczegolyDataReader, jak poniżej: Przykład 23. Deklaracja globalnej zmiennej wykorzystywanej przy wiązaniu danych System.Data.OleDb.OleDbDataReader SzczegolyDataReader; 15. Przejdź na zakładkę Design i zaznacz kontrolkę TxtDomowy. Znajdź na samej górze okienka z listą właściwości kolekcję powiązań z danymi (DataBindigs). Otwórz okienko TxtDomowy Bindings, klikając w przycisk z wielokropkiem. 16. Na liście Bindable Properties wskaż właściwość Text (jest domyślnie zaznaczona). Kliknij w przycisk radiowy Custom binding expression i wpisz w okienku poniżej następujące wyrażenie wiążące: SzczegolyDataReader["domowy"] 17. Kliknij w przycisk OK. 18. Zaznacz kontrolkę TxtKomorkowy. Znajdź kolekcję powiązań z danymi (DataBindigs). Otwórz okienko TxtKomorkowy Bindings, klikając w przycisk z wielokropkiem. 19. Na liście Bindable Properties wskaż właściwość Text (jest domyślnie zaznaczona). Kliknij w przycisk radiowy Custom binding expression i wpisz w okienku poniżej następujące wyrażenie wiążące: SzczegolyDataReader["komorkowy"] 20. Kliknij w przycisk OK. 21. Zaznacz kontrolkę LnkEmail. Znajdź kolekcję powiązań z danymi (DataBindigs). Otwórz okienko LnkEmail Bindings, klikając w przycisk z wielokropkiem. 22. Na liście Bindable Properties wskaż właściwość Text (jest domyślnie zaznaczona). Kliknij w przycisk radiowy Custom binding expression i wpisz w okienku poniżej następujące wyrażenie wiążące: (SzczegolyDataReader["email"].ToString() == "") ? "(brak)" : SzczegolyDataReader["email"] 23. Wyrażenie to wyświetla adres e-mail, o ile jest podany. W przeciwnym przypadku wyświetla napis „(brak)”. 24. Na liście Bindable Properties wskaż teraz właściwość NavigateUrl. Kliknij w przycisk radiowy Custom binding expression i wpisz w okienku poniżej następujące wyrażenie 20 Obsługa baz danych z użyciem ADO.NET wiążące: (SzczegolyDataReader["email"].ToString() == "") ? "" : "mailto:" + SzczegolyDataReader["email"] 25. Wyrażenie to konstruuje wartość atrybutu href dla odnośnika (znacznika <a>), w postaci gotowego do kliknięcia łącza. Składają się na nie napis mailto: oraz adres e-mail, o ile jest podany. W przeciwnym przypadku adres docelowy łącza będzie pusty. 26. Pozostaje jeszcze w odpowiednim momencie zażądać powiązania kontrolek z danymi. Dodaj więc dla strony (Page) obsługę zdarzenia PreRender. Jest to moment, w którym wszystko na stronie jest już zrobione, ale generowanie kodu HTML dla kontrolek jeszcze się nie rozpoczęło. Wpisz w treści metody poniższy kod: Przykład 24. Odczyt z bazy danych szczegółów wybranego klienta void Page_PreRender(object sender, EventArgs e) { if (PanelSzczegoly.Visible) { int id; try { id = Convert.ToInt32(DdLstId.SelectedItem.Value); } catch (Exception ex) { // Zabezpieczenie przed brakiem danych w kontrolce DdLstId id = 0; } // Odczytanie szczegółów wybranego klienta SzczegolyDataReader = (System.Data.OleDb.OleDbDataReader) SzczegolyKlienta(id); // Wiązanie kontrolek z danymi if (SzczegolyDataReader.HasRows) { SzczegolyDataReader.Read(); TxtDomowy.DataBind(); TxtKomorkowy.DataBind(); LnkEmail.DataBind(); } } } 21 Obsługa baz danych z użyciem ADO.NET 27. Zapisz dokonane zmiany i sprawdź działanie strony. Podsumowując należy zauważyć, że do wyświetlania szczegółów klienta na powyższej stronie zostały użyte aż trzy mechanizmy: odczyt danych przez DataSet (imię i nazwisko), odczyt danych przez DataReader (adres) oraz wiązanie kontrolek z danymi (telefony i e-mail). Mimo to, wszystkie szczegóły klienta można było wyświetlić jedną z tych trzech metod. Wykorzystanie wszystkich mechanizmów naraz miało tylko na celu prezentację ich możliwości. 22 Obsługa baz danych z użyciem ADO.NET 6. Złożone operacje na danych Użycie i konfiguracja kontrolki DataGrid Pierwszym sposobem szybkiego wyświetlenia danych na stronie było użycie kontrolki MxDataGrid. Zobaczysz teraz, jakie możliwości daje w praktyce tradycyjna siatka danych, czyli kontrolka ASP.NET DataGrid. Stworzysz teraz stronę z taką kontrolką, dzięki czemu będzie można nie tylko przeglądać dane, ale także je zmieniać — z możliwością zatwierdzenia lub porzucenia zmian. Rysunek 7. Strona zawierająca siatkę danych, z możliwością edycji W tym celu wykonaj poniższe czynności: 1. Rozpocznij od otworzenia strony Default.aspx z katalogu bank. 2. Pod umieszczoną tam kontrolką MxDataGrid wstaw odnośnik do strony, na której będzie można dokonywać przeglądu i edycji tych samych danych. Odnośnik wstaw poleceniem HTML Insert HyperLink, zaś w wyświetlonym oknie wpisz następujące dane: Edycja danych (dla Description) oraz DaneKlientow.aspx (dla URL). Możesz zamknąć plik Default.aspx. 3. Otwórz plik Strona.aspx z podkatalogu temp i zapisz kopię tego pliku w podkatalogu bank projektu, pod nazwą DaneKlientow.aspx. 23 Obsługa baz danych z użyciem ADO.NET Przejdź na zakładkę HTML i popraw ścieżki do plików włączanych: 4. <!-- #Include file="Header.txt" --> na: <!-- #Include file="../Header.txt" --> oraz: <!-- #Include file="Footer.txt" --> na: <!-- #Include file="../Footer.txt" --> 5. Wróć do zakładki Design i zmień tytuł strony na Dane klientów. 6. Wstaw na stronę przed napisem treść kontrolkę AccessDataSourceControl i nazwij ją (właściwość (ID)) Select_klienci. 7. Usuń napis treść i wstaw kontrolkę DataGrid. Nazwij ją GridKlienci. 8. Wstaw w następnym akapicie odnośnik do poprzedniej strony, na której można tylko przeglądać dane klientów. Odnośnik wstaw poleceniem HTML Insert HyperLink, zaś w wyświetlonym oknie wpisz następujące dane: Zakończenie edycji (dla Description) oraz Default.aspx (dla URL). Stwórz dla strony (Page) obsługę zdarzenia Load. Wpisz kod ustawiający łańcuch 9. połączenia z bazą danych oraz wiążący siatkę z danymi przy ładowaniu strony: Przykład 25. Ustawianie właściwości ConnectionString i wiązanie danych przy pierwszym ładowaniu strony void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { Select_klienci.ConnectionString = ConfigurationSettings.AppSettings["connectionstring"]; GridKlienci.DataBind(); } } 10. Otwórz plik konfiguracyjny aplikacji web.config i skopiuj łańcuch połączenia do bazy danych bank.mdb (wartość atrybutu value klucza connectionstring – tekst pomiędzy cudzysłowami). Możesz po tym zamknąć plik web.config. 11. Przełącz się na zakładkę Design i wklej skopiowany łańcuch połączenia do właściwości ConnectionString kontrolki Select_klienci. Mimo że jest to wbrew stosowanej w tym module praktyce, istnieją dwie przyczyny uzasadniające takie rozwiązanie. Po pierwsze — dzięki temu Web Matrix pozwoli lepiej skonfigurować kontrolkę GridKlienci. Po drugie — nadpisywanie w zdarzeniu Page_Load właściwości ConnectionString wartością odczytaną z pliku 24 Obsługa baz danych z użyciem ADO.NET konfiguracyjnego zabezpiecza przed problemami wynikającymi z pozostawienia ścieżki do bazy danych w kodzie strony. Dobrą praktyką będzie natomiast usunięcie tej ścieżki po skończeniu pracy nad stroną. 12. Ustaw pozostałe właściwości kontrolek zgodnie z poniższą tabelą. Zauważ moment połączenia z bazą danych oraz to, jak zmienia się zawartość siatki danych GridKlienci po zmianie jej właściwości DataSource: Typ kontrolki AccessDataSourceControl DataGrid Nazwa właściwości (ID) ConnectionString SelectCommand (ID) AutoGenerateColumns DataSource Wartość właściwości Select_klienci odczytany z pliku web.config SELECT * FROM [klienci] GridKlienci False Select_klienci 13. Pod okienkiem właściwości znajdź link Property Builder i kliknij w niego. 14. Na zakładce General w liście rozwijanej Data key field wskaż element id. 15. Na zakładce Columns rozwiń węzeł drzewa nazwany Button Column. Kliknij w element Edit, Update, Cancel, a następnie w przycisk > . Do siatki danych zostanie dodana pierwsza kolumna, pozwalająca na wykonywanie operacji edycji oraz zatwierdzanie bądź anulowanie wprowadzonych zmian. 16. Ustaw napisy wyświetlane podczas pracy: Edit Text na: Edycja, UpdateText na: Zapisz, Cancel Text na: Anuluj. 17. Wskaż w liście Available columns pod węzłem Data Fields element All Fields i — wciskając przycisk > — dodaj wszystkie kolumny. 18. Ustaw napisy wyświetlane w nagłówkach kolumn, klikając kolejno w nazwy kolumn w prawej liście Selected Columns. Zmień właściwość Header text dla kolumn odpowiednio na: id Nr, imie Imię, nazwisko Nazwisko, adres Ulica, kod Kod, miasto Miasto, kraj Kraj, domowy Tel. domowy, komorkowy Tel. komórkowy, email e-mail. 19. Na zakładce Format wskaż w liście Objects pozycję DataGrid i ustaw jej właściwość Back color na wybrany kolor (sugestia: Bisque). 20. Podobnie wskaż w liście Objects pozycję Header i ustaw jej właściwość Back color na inny wybrany kolor (sugestia: SandyBrown). 21. Wciśnij przycisk Apply u dołu okna, aby zobaczyć wprowadzone zmiany. Jeśli wolisz inne kolory, możesz je dowolnie zmieniać. 25 Obsługa baz danych z użyciem ADO.NET 22. Na zakładce Borders z listy rozwijanej Grid Lines wybierz wartość Both (wartość domyślna) oraz ustaw właściwość Border Color na wybrany kolor (sugestia: Gray). 23. Zatwierdź zmiany przyciskiem OK. 24. Zapisz stronę i uruchom ją. Kontrolka DataGrid powinna wyświetlić dane z tabeli klienci, ale edycja danych jeszcze nie będzie możliwa. Niebawem się to zmieni. Edycja i anulowanie edycji 25. W celu umożliwienia przejścia do edycji danych w kontrolce DataGrid, w obsłudze zdarzenia rozpoczęcia edycji należy programowo ustawić jej właściwość EditItemIndex. Przejdź następnie do zakładki Design i zaznacz kontrolkę GridKlienci. 26. Dodaj dla kontrolki GridKlienci obsługę zdarzenia EditCommand. Wpisz poniższy kod: Przykład 26. Przejście do edycji wiersza w siatce danych DataGri void GridKlienci_EditCommand(object sender, DataGridCommandEventArgs e) { GridKlienci.EditItemIndex = e.Item.ItemIndex; GridKlienci.DataBind(); } 27. Wróć do zakładki Design i dodaj dla kontrolki GridKlienci także obsługę zdarzenia CancelCommand. Wpisz poniższy kod: Przykład 27. Przejście do edycji wiersza w siatce danych DataGrid void GridKlienci_CancelCommand(object sender, DataGridCommandEventArgs e) { GridKlienci.EditItemIndex = -1; GridKlienci.DataBind(); } 28. Zapisz i uruchom stronę. Powinno dać się edytować dane i anulować edycję. Zapisywanie danych Teraz dodasz jeszcze możliwość zapisywania zmian. Najpierw jednak musisz utworzyć kod, który będzie zapisywał zmiany do bazy danych. 29. Przełącz się na zakładkę Code i z zakładki Code Wizards znajdującej się w oknie Toolbox przeciągnij generator kodu UPDATE Data Method poniżej metody GridKlienci_CancelCommand. 26 Obsługa baz danych z użyciem ADO.NET 30. Na ekranie pojawi się okno dialogowe Select a Database Connection. W polu Select a database wybierz połączenie z bazą danych bank.mdb (jeśli jest otwarta) lub wskaż pozycję <New Database Connection> i wciśnij przycisk Create..., aby stworzyć nowe połączenie do tej bazy. 31. Kliknij w przycisk Next. 32. Na ekranie pojawi się okno dialogowe Construct an UPDATE query, prezentujące pierwszy ekran kreatora generacji kodu. 33. W liście kolumn zaznacz: imie, nazwisko, adres, kod, miasto, kraj, domowy, komorkowy oraz email. Za każdym razem musisz podać nazwę parametru, który będzie użyty w wyrażeniu SQL. Domyślne wartości są całkowicie wystarczające. 34. Kliknij w przycisk WHERE. 35. Kliknij w przycisk OK. 36. Kliknij w przycisk Next. 37. Jeśli chcesz, możesz sprawdzić budowę zapytania klikając przycisk Test Query. 38. Kliknij w przycisk Next. 39. W polu nazwy metody wpisz ZapiszDaneKlienta. 40. Kliknij w przycisk Finish. 41. Wygenerowany w ten sposób kod ma wpisaną pełną ścieżkę dostępu do pliku bank.mdb. Popraw początek metody ZapiszDaneKlienta, aby ścieżka do bazy była odczytywana z pliku web.config. Popraw również treść zapytania queryString: Przykład 28. Zapisanie zmienionych danych wskazanego klienta int ZapiszDaneKlienta(int id, string imie, string nazwisko, string adres, string kod, string miasto, string kraj, string domowy, string komorkowy, string email) { string connectionString = ConfigurationSettings.AppSettings["connectionstring"]; System.Data.IDbConnection dbConnection = new System.Data.OleDb.OleDbConnection(connectionString); string queryString = "UPDATE [klienci] SET [imie]=@imie, " + "[nazwisko]=@nazwisko, [adres]=@adres, [kod]=@kod, " + "[miasto]=@miasto, [kraj]=@kraj, [domowy]=@domowy, " + "[komorkowy]=@komorkowy, [email]=@email " + "WHERE ([klienci].[id] = @id)"; ... 27 Obsługa baz danych z użyciem ADO.NET 42. W pewnych przypadkach występuje mimo wszystko problem — tak skonstruowane zapytanie nie zapisuje modyfikacji w bazie. W takim wypadku przenieś dodatkowo definicję parametru @id na koniec listy parametrów: Przykład 29. Przeniesienie parametru @id na koniec listy parametrów ... dbCommand.CommandText = queryString; dbCommand.Connection = dbConnection; System.Data.IDataParameter dbParam_id = new System.Data.OleDb.OleDbParameter(); dbParam_id.ParameterName = "@id"; dbParam_id.Value = id; dbParam_id.DbType = System.Data.DbType.Int32; dbCommand.Parameters.Add(dbParam_id); System.Data.IDataParameter dbParam_imie = new System.Data.OleDb.OleDbParameter(); ... dbParam_email.DbType = System.Data.DbType.String; dbCommand.Parameters.Add(dbParam_email); System.Data.IDataParameter dbParam_id = new System.Data.OleDb.OleDbParameter(); dbParam_id.ParameterName = "@id"; dbParam_id.Value = id; dbParam_id.DbType = System.Data.DbType.Int32; dbCommand.Parameters.Add(dbParam_id); int rowsAffected = 0; dbConnection.Open(); ... 43. Wróć do zakładki Design i dodaj dla kontrolki GridKlienci obsługę zdarzenia UpdateCommand. Wpisz poniższy kod: Przykład 30. Kod testujący przysyłane parametry w obsłudze zdarzenia UpdateCommand void GridKlienci_UpdateCommand(object sender, DataGridCommandEventArgs e) { // Wyświetlenie przysłanych parametrów. UKRYĆ W KOMENTARZU! string s = ""; for (int i = 0; i < Request.Form.Count; i++) 28 Obsługa baz danych z użyciem ADO.NET s += "[" + i + "]=" + Request.Form[i] + "<br>"; Status.Text = s; Status.Visible = true; // Zakończenie edycji GridKlienci.EditItemIndex = -1; GridKlienci.DataBind(); } 44. Po zakończeniu edycji i naciśnięciu łącza Zapisz do strony wysyłane są parametry formularza edycyjnego. Są one umieszczane w tablicy Request.Form. 45. W powyższym kodzie zaznaczona jest sekcja wyświetlająca w etykiecie Status indeksy w tablicy Request.Form oraz wartości przysłanych w ten sposób parametrów. Jest to kod testujący, który należy usunąć lub ukryć w komentarzu po zakończeniu pracy nad stroną. 46. Zapisz zmiany, wywołaj edycję wiersza z siatki danych i naciśnij łącze Zapisz. 47. Zauważ, że pod indeksem [3] przysyłany jest numer klienta, zaś pod indeksami od [4] do [12] pozostałe parametry. 48. Pojawia się jednak mały problem. Kolumna id z numerem klienta jest niestety dostępna do edycji. Można więc wpisać tam inną liczbę i spowodować, że zostanie wysłane żądanie zmiany danych innego klienta. Aby sobie z tym poradzić, trzeba znaleźć rozwiązanie, które w trybie edycji pozwala jedynie zobaczyć numer klienta (nie pozwalając na jego zmianę), ale aby równocześnie numer nadal był wysyłany z pozostałymi danymi. 49. Przełącz się więc ponownie na zakładkę Design i zaznacz kontrolkę GridKlienci. Znajdź link Property Builder i kliknij w niego. 50. W zakładce Columns, w liście Selected Columns, zaznacz kolumnę Nr. Kliknij w link znajdujący się na dole okna Convert this column into a Template Column. 51. Naciśnij przycisk OK i przejdź do zakładki HTML. 52. Zauważ, że zamiast dotychczas umieszczonej tam kolumny <asp:BoundColumn> pojawiła się kolumna <asp:TemplateColumn>. Jest to kolumna, która posiada dwie sekcje definiujące jej zawartość: <ItemTemplate> dla wyświetlania danych oraz <EditItemTemplate> dla edycji danych. 53. Zmień definicję kolumny Nr na poniższą: 29 Obsługa baz danych z użyciem ADO.NET Przykład 31. Zmiana zawartości kolumny Nr dla edycji danych ... <asp:EditCommandColumn ButtonType="LinkButton" UpdateText="Zapisz" CancelText="Anuluj" EditText="Edycja"></asp:EditCommandColumn> <asp:TemplateColumn HeaderText="Nr"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container, "DataItem.id") %>'> </asp:Label> </ItemTemplate> <EditItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container, "DataItem.id") %>'> </asp:Label> <input type="hidden" name="klient_id" value='<%# DataBinder.Eval(Container, "DataItem.id") %>'> </EditItemTemplate> </asp:TemplateColumn> <asp:BoundColumn DataField="imie" HeaderText="Imię"></asp:BoundColumn> ... 54. Wprowadzona modyfikacja polega na zamianie w sekcji <EditItemTemplate> kontrolki TextBox na Label oraz na dodaniu dodatkowego pola ukrytego, o nazwie klient_id i zawartości takiej samej jak poprzedzająca go etykietka. W efekcie dostępne jest już tylko wyświetlanie danych zamiast ich edycji. 55. Zapisz zmiany i sprawdź, czy osiągnięty został założony cel — po wejściu do edycji i naciśnięciu linku Zapisz nadal są przysyłane takie same parametry, ale nie można zmieniać numeru klienta. 56. Zmień definicję metody GridKlienci_UpdateCommand jak poniżej: Przykład 32. Zapisanie danych po zakończeniu edycji void GridKlienci_UpdateCommand(object sender, DataGridCommandEventArgs e) { /********************************************************** // Wyświetlenie przysłanych parametrów. UKRYĆ W KOMENTARZU! string s = ""; for (int i = 0; i < Request.Form.Count; i++) s += "[" + i + "]=" + Request.Form[i] + "<br>"; 30 Obsługa baz danych z użyciem ADO.NET Status.Text = s; Status.Visible = true; **********************************************************/ // Zapisanie danych if (Request.Form.Count >= 12) { ZapiszDaneKlienta(Convert.ToInt32(Request.Form[3]), Request.Form[4], Request.Form[5], Request.Form[6], Request.Form[7], Request.Form[8], Request.Form[9], Request.Form[10], Request.Form[11], Request.Form[12]); } // Zakończenie edycji GridKlienci.EditItemIndex = -1; GridKlienci.DataBind(); } 31