Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00223 007405 11068520 na godz. na dobę w sumie
C# 3.0 i .NET 3.5. Technologia LINQ - książka
C# 3.0 i .NET 3.5. Technologia LINQ - książka
Autor: Liczba stron: 88
Wydawca: Helion Język publikacji: polski
ISBN: 83-246-1447-8 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> c# - programowanie
Porównaj ceny (książka, ebook, audiobook).

Poznaj technologię LINQ

aby uzyskać swobodny dostęp do danych z SQL Server, pliku XML lub kolekcji z poziomu swoich programów

Zastosowanie technologii LINQ (ang. Language-Integrated Query, zintegrowany język zapytań) w zasadniczy sposób upraszcza projektowanie aplikacji bazodanowych. Zapytanie LINQ zwraca kolekcję z przestrzeni nazw typów ogólnych. Kolekcja ta może być modyfikowana, a następnie zwrócona do źródła. Dzięki temu zachowywana jest pełna kontrola typów danych i ich konwersji w poszczególnych mechanizmach pośredniczących w pobieraniu danych.

Książka 'C# 3.0 i .NET 3.5. Technologia LINQ' prezentuje prosty sposób korzystania ze zintegrowanego języka zapytań. Dzięki temu podręcznikowi nauczysz się pobierać dane z różnego rodzaju źródeł; tworzyć pliki XML w nowy, bardziej intuicyjny sposób; stosować składowane rozszerzenia, nowego typu metody (oraz odpowiadające im operatory), zdefiniowane w najnowszej wersji języka C#. Ponadto dowiesz się, jak tworzyć własne źródła danych LINQ. Krótko mówiąc, z książką 'C# 3.0 i .NET 3.5. Technologia LINQ' nawet jako średnio zaawansowany programista poradzisz sobie ze stworzeniem bardzo skomplikowanych aplikacji bazodanowych.

Ta książka wskaże Ci prosty sposób tworzenia doskonałych i nowoczesnych aplikacji bazodanowych.

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

C# 3.0 i .NET 3.5. Technologia LINQ Autor: Jacek Matulewski ISBN: 83-246-1447-8 Format: 158x235, stron: 88 Poznaj technologiŒ LINQ aby uzyska(cid:230) swobodny dostŒp do danych z SQL Server, pliku XML lub kolekcji z poziomu swoich program(cid:243)w (cid:149) Bezpieczny dostŒp do danych przy zachowaniu kontroli typ(cid:243)w (cid:149) Tworzenie zapytaæ LINQ (cid:149) Budowanie, analiza i pobieranie danych z plik(cid:243)w XML Zastosowanie technologii LINQ (ang. Language-Integrated Query, zintegrowany jŒzyk zapytaæ) w zasadniczy spos(cid:243)b upraszcza projektowanie aplikacji bazodanowych. Zapytanie LINQ zwraca kolekcjŒ z przestrzeni nazw typ(cid:243)w og(cid:243)lnych. Kolekcja ta mo¿e by(cid:230) modyfikowana, a nastŒpnie zwr(cid:243)cona do (cid:159)r(cid:243)d‡a. DziŒki temu zachowywana jest pe‡na kontrola typ(cid:243)w danych i ich konwersji w poszczeg(cid:243)lnych mechanizmach po(cid:156)rednicz„cych w pobieraniu danych. Ksi„¿ka (cid:132)C# 3.0 i .NET 3.5. Technologia LINQ(cid:148) prezentuje prosty spos(cid:243)b korzystania ze zintegrowanego jŒzyka zapytaæ. DziŒki temu podrŒcznikowi nauczysz siŒ pobiera(cid:230) dane z r(cid:243)¿nego rodzaju (cid:159)r(cid:243)de‡; tworzy(cid:230) pliki XML w nowy, bardziej intuicyjny spos(cid:243)b; stosowa(cid:230) sk‡adowane rozszerzenia ? nowego typu metody (oraz odpowiadaj„ce im operatory), zdefiniowane w najnowszej wersji jŒzyka C#. Ponadto dowiesz siŒ, jak tworzy(cid:230) w‡asne (cid:159)r(cid:243)d‡a danych LINQ. Kr(cid:243)tko m(cid:243)wi„c, z ksi„¿k„ (cid:132)C# 3.0 i .NET 3.5. Technologia LINQ(cid:148) nawet jako (cid:156)rednio zaawansowany programista poradzisz sobie ze stworzeniem bardzo skomplikowanych aplikacji bazodanowych. (cid:149) Wyra¿enia Lambda (cid:149) Nowe operatory LINQ (cid:149) Zapytania LINQ (cid:149) LINQ to DataSet (cid:149) Aktualizacja danych w bazie (cid:149) Korzystanie z rozszerzeæ (cid:149) Kontrolka LinqDataSource (cid:149) Tworzenie i modyfikacja pliku XML (cid:149) Tworzenie (cid:159)r(cid:243)de‡ danych LINQ Ta ksi„¿ka wska¿e Ci prosty spos(cid:243)b tworzenia doskona‡ych i nowoczesnych aplikacji bazodanowych Wydawnictwo Helion ul. Ko(cid:156)ciuszki 1c 44-100 Gliwice tel. 032 230 98 63 e-mail: helion@helion.pl Spis treĈci Wstöp .............................................................................................. 5 Rozdziaä 1. NowoĈci jözyka C# 3.0 ..................................................................... 7 OkreĞlanie typu zmiennej lokalnej przy inicjalizacji ........................................................ 7 WyraĪenia Lambda ........................................................................................................... 8 Rozszerzenia ................................................................................................................... 10 Nowa forma inicjalizacji obiektów i tablic ..................................................................... 12 Nowe operatory LINQ .................................................................................................... 13 Typy anonimowe ............................................................................................................ 14 Przykáad — kolekcja jako Ĩródáo danych ....................................................................... 14 Rozdziaä 2. LINQ i ADO.NET .............................................................................. 21 Konfiguracja kontrolki DataSet ...................................................................................... 22 LINQ to DataSet, czyli tam i z powrotem .......................................................................... 24 KorzyĞci z LINQ to DataSet ........................................................................................... 26 Rozdziaä 3. LINQ i SQL Server ........................................................................... 29 Klasa encji ...................................................................................................................... 29 Pobieranie danych .......................................................................................................... 31 Aktualizacja danych w bazie .......................................................................................... 32 Wizualne projektowanie klasy encji ............................................................................... 35 Korzystanie z procedur skáadowanych ........................................................................... 44 Kontrolka LinqDataSource (ASP.NET) ......................................................................... 47 Rozdziaä 4. LINQ i XML .................................................................................... 51 Tworzenie pliku XML za pomocą klas XDocument i XElement ................................... 51 Pobieranie wartoĞci z elementów o znanej pozycji w drzewie ....................................... 54 Przenoszenie danych z kolekcji do pliku XML .............................................................. 55 Przenoszenie danych z bazy danych (komponentu DataSet) do pliku XML .................. 56 Zapytania LINQ .............................................................................................................. 57 Modyfikacja pliku XML ................................................................................................. 59 Rozdziaä 5. Tworzenie Ēródeä danych LINQ ......................................................... 61 IEnumerable ................................................................................................................... 61 IEnumerable T ............................................................................................................ 63 Oddzielenie Ĩródáa od jego interfejsu ............................................................................. 65 IQueryable i IOrderedQueryable .................................................................................... 68 4 C# 3.0 i .NET 3.5. Technologia LINQ IQueryable T i IOrderedQueryable T ...................................................................... 69 Drzewo wyraĪenia .......................................................................................................... 71 Zadanie. LINQ to TXT ................................................................................................... 78 Dodatek A Wiöcej w sieci… ............................................................................ 83 Skorowidz ...................................................................................... 85 Rozdziaä 3. LINQ i SQL Server Wspominając o technologii LINQ, mówi siĊ zazwyczaj o zanurzeniu jĊzyka SQL w jĊ- zyku C#. W przypadku LINQ to SQL zanurzenie to moĪna rozumieü niemal dosáownie — zapytanie LINQ jest w tym przypadku táumaczone bezpoĞrednio na zapytanie SQL wysyáane do bazy danych. Zacznijmy od prostej sytuacji: poáączmy siĊ z bazą danych Telefony.mdf (zob. rysunek 2.3 z poprzedniego rozdziaáu) i pobierzmy z niej listĊ osób peánoletnich. Wykorzystamy do tego obiekt klasy DataContext, która jak na razie wspóápracuje tylko z bazami SQL Server (nie dotyczy to jednak lokalnych baz SQL Server Compact Edition). Klasa DataContext jest gáówną bramą do technologii LINQ to SQL. Brama ta wymaga jednak straĪnika. Jego rolĊ przejmuje klasa encji, tj. klasa C#, która zdefiniuje typ kaĪdego rekordu (encji) tabeli bazy danych. DziĊki tej klasie moĪliwe jest zbudowanie pomostu miĊdzy tabelą pobie- raną za pomocą zapytania SQL a kolekcją zwracaną przez zapytanie LINQ, tj. miĊdzy typem encji a typem elementu kolekcji. DziĊki tej klasie w zapytaniu LINQ moĪemy uĪywaü nazw pól, które obecne są w tabeli, wrĊcz identyfikowaü kolekcjĊ z tabelą. Zanim przejdziemy do konkretów, chciaábym jeszcze zwróciü uwagĊ Czytelnika na je- den istotny fakt. W LINQ to Object, które poznaliĞmy w pierwszym rozdziale, Ĩródáem danych byáa kolekcja istniejąca w pamiĊci i w peáni dostĊpna z poziomu programu. Nie byáo zatem koniecznoĞci odwoáywania do zasobów zewnĊtrznych (np. plików bazy danych). DziĊki temu caáy kod aplikacji mógá byü skompilowany do kodu poĞredniego. W przy- padku LINQ to SQL, którym zajmiemy siĊ w tym rozdziale, lub LINQ to XML, omówio- nego w kolejnym rozdziale, taka peána kompilacja nie jest moĪliwa. Analiza danych pobranych ze Ĩródáa danych moĪe odbyü siĊ dopiero w trakcie dziaáania programu. Realizowane jest to za pomocą drzewa zapytaĔ, które poznamy dokáadniej w ostatnim rozdziale, przy okazji projektowania wáasnego Ĩródáa danych LINQ. Klasa encji Klasa encji (ang. entity class) to zwykáa klasa C#, w której za pomocą atrybutów po- wiązane są pola klasy z polami tabeli (kolumnami). Mamy wiĊc do czynienia z mode- lowaniem zawartoĞci relacyjnej bazy danych w typowanych klasach jĊzyka, w którym 30 C# 3.0 i .NET 3.5. Technologia LINQ przygotowujemy program. W tym kontekĞcie uĪywany jest angielski termin strongly typed, który podkreĞla izomorficznoĞü relacji klasy encji i struktury tabeli. Ów zwią- zek jest niezwykle istotny — przede wszystkim umoĪliwia kontrolĊ typów, która w pewnym sensie rozciąga siĊ na poáączenie z bazą danych. DziĊki tej relacji progra- mista moĪe w pewnym stopniu utoĪsamiaü tĊ klasĊ i reprezentowaną przez nią tabelĊ. To pozwala równieĪ przygotowywaü zapytania LINQ, korzystając z nazw pól tabeli — jego táumaczenie na zapytanie SQL jest dziĊki temu szczególnie proste, a jedno- czeĞnie w peáni zachowana jest kontrola typów. DomyĞlne wiązanie realizowane jest na podstawie nazw obu pól. MoĪliwa jest jednak zmiana tego domyĞlnego sposobu wiązania oraz zmiana wáasnoĞci poszczególnych pól. Przed caáą klasą znaleĨü siĊ powinien atrybut Table z przestrzeni nazw System.Data. ´Linq.Mapping, w którym wskazujemy nazwĊ tabeli z bazy danych1. Natomiast przed polami odpowiadającymi kolumnom w tabeli naleĪy umieĞciü atrybut Column (z tej sa- mej przestrzeni nazw), w którym moĪemy wskazaü m.in. nazwĊ kolumny w tabeli (pa- rametr Name), poinformowaü go, czy jest kluczem gáównym (IsPrimaryKey) lub czy moĪe przyjmowaü puste wartoĞci (CanBeNull). Listing 3.1 zawiera przykáad klasy encji, w której definiujemy typ rekordu z tabeli ListaOsob z bazy danych Telefony.mdf zna- nej z poprzedniego rozdziaáu.2 Listing 3.1. Klasa encji związana z tabelą ListaOsob z bazy Telefony.mdf [Table(Name = ListaOsob )] public class Osoba { [Column(Name = Id , IsPrimaryKey = true)] public int Id; [Column(Name = Imiú , CanBeNull = false)] public string Imiú; [Column(Name = Nazwisko , CanBeNull = false)] public string Nazwisko; [Column] public int NumerTelefonu; [Column] public int Wiek; } W powyĪszym listingu wiązanie klasy ze strukturą bazy danych przeprowadzane zo- staje na podstawie atrybutów doáączanych do definicji klasy. W terminologii Microsoft nazywane jest to mapowaniem opartym na atrybutach (ang. attribute-based mapping). 1 Klasy z przestrzeni nazw System.Data.Linq i jej podprzestrzeni, m.in. z System.Data.Linq.Mapping, do której naleĪy klasa Table, zdefiniowane są w osobnej bibliotece System.Data.Linq.dll, naleĪącej do zbioru bibliotek platformy .NET 3.5. DomyĞlnie nie jest ona wáączana do zbioru bibliotek projektu. NaleĪy ją zatem dodaü samodzielnie, korzystając z polecenia Project, Add Reference…. Omówione niĪej narzĊdzie wizualnego projektowania klas encji zwolni nas z tego obowiązku. 2 Tworząc tabelĊ w bazie SQL Server mogliĞmy zezwoliü, aby niektóre jej pola dopuszczaáy pustą wartoĞü. Definiując klasĊ encji warto zadeklarowaü odpowiadające im pola klasy w taki sposób, aby dopuszczaáy przypisanie wartoĞci null. W przypadku áaĔcuchów nie ma problemu – typ String jest typem referencyjnym i zawsze moĪna mu przypisaü wartoĞü null. Inaczej wygląda to np. w przypadku typu int, który jest typem wartoĞciowym. NaleĪy wówczas w deklaracji pola wykorzystaü typ parametryczny Nullable int . Rozdziaä 3. i LINQ i SQL Server 31 MoĪliwe jest równieĪ podejĞcie alternatywne, w którym mapowanie odbywa siĊ na podstawie struktury zapisanej w pliku XML. Takie podejĞcie nosi nazwĊ mapowania zewnĊtrznego i nie bĊdĊ siĊ nim tu zajmowaá. Po jego opis warto zajrzeü na stronĊ MSDN: http://msdn2.microsoft.com/en-us/library/bb386907.aspx. LINQ to SQL daje dobry pretekst do wspomnienia o zagadnieniu modelowania da- nych. Jest to ciekawa gaäñĒ informatyki, ale nie chciaäbym snuè dygresji na jej temat. Osoby zainteresowane teoriñ przechowywania danych powinny w Google wpisaè hasäo data modeling lub modelowanie danych. Jak wspomniaáem wczeĞniej, klasa encji zwykle nie jest tworzona rĊcznie. Zwykle do jej projektowania wykorzystywany jest edytor O/R Designer, który omówiĊ w dalszej czĊĞci tego rozdziaáu. Wydaje mi siĊ jednak, Īe przy pierwszych próbach korzystania z technologii LINQ to SQL warto zrobiü wszystko samodzielnie. Dotyczy to równieĪ powoáywania instancji klasy DataContext, czym zajmiemy siĊ juĪ za chwilĊ. Pobieranie danych Zacznijmy od zdefiniowania pól przechowujących referencje do instancji klasy Data ´Context i jej tabeli ListaOsob: static string nazwaPliku = Telefony.mdf ; static DataContext bazaDanychTelefony = ´new DataContext(System.IO.Path.GetFullPath(nazwaPliku)); static Table Osoba listaOsob = bazaDanychTelefony.GetTable Osoba (); Tworzymy obiekt DataContext i pobieramy z niego referencjĊ do tabeli (klasa Table parametryzowana klasą encji Osoba). Klasa DataContext znajduje siĊ w przestrzeni 3. Ostat- nazw System.Data.Linq, naleĪy wiĊc uwzglĊdniü ją w grupie poleceĔ using nia instrukcja tworzy pole o nazwie listaOsob typu Table parametryzowanego naszą klasą encji Osoba. Referencja ta bĊdzie umoĪliwiaü dostĊp do danych pobranych z tabeli ListaOsob. Nazwa pobieranej tabeli wskazana zostaáa w atrybucie Table, którym poprze- dziliĞmy klasĊ encji. Dlatego jej nazwa nie pojawia siĊ w powyĪszych definicjach. Obiekt klasy DataContext reprezentuje bazĊ danych. Z kolei klasa encji zdefiniowana w listingu 3.1 dostarcza informacji o strukturze konkretnej tabeli (encji). DziĊki obu klasom moĪemy poáączyü siĊ z bazą danych i pobraü dane z interesującej nas tabeli. Prezentuje to listing 3.2. Listing 3.2. Pobieranie danych z tabeli w bazie SQL Server za pomocą LINQ to SQL private void button1_Click(object sender, EventArgs e) { //pobieranie kolekcji var listaOsobPelnoletnich = from osoba in listaOsob 3 Tu stosuje siĊ równieĪ uwaga z poprzedniego przypisu. Ponadto konstruktor klasy DataContext wymaga, aby ĞcieĪka do pliku podana w argumencie byáa bezwzglĊdna (ang. full path). 32 C# 3.0 i .NET 3.5. Technologia LINQ where osoba.Wiek =18 select osoba; //wyĞwietlanie pobranej kolekcji string s = Lista osób peđnoletnich: ; foreach (Osoba osoba in listaOsobPelnoletnich) s+=osoba.Imiú+ +osoba.Nazwisko ´+ ( +osoba.Wiek+ ) ; MessageBox.Show(s); } W zapytaniu LINQ (pierwsza instrukcja metody widocznej w listingu 3.2) pobiera z ta- beli listĊ osób, które mają co najmniej 18 lat. Zwróümy uwagĊ na podobieĔstwo tego zapytania do tego, które stosowaliĞmy w przypadku LINQ to Objects w pierwszym roz- dziale. W listingu 3.2 klasa encji Osoba pojawia siĊ tylko raz w pĊtli foreach. Co wiĊcej, skoro jest jasne, Īe kaĪdy rekord jest obiektem typu Osoba, a to wiadomo dziĊki parametry- zacji pola listaOsob, jawne wskazanie typu w tej pĊtli nie jest konieczne i z równym skutkiem moglibyĞmy uĪyü sáowa kluczowego var — kompilator sam wywnioskowaáby, z jakim typem ma do czynienia. Aktualizacja danych w bazie Pobieranie danych, wizytówka LINQ, to zwykle pierwsza czynnoĞü wykonywana przez aplikacje. Technologia LINQ to SQL nie poprzestaje tylko na tym. Zmiany wprowa- dzone w pobranej zapytaniem LINQ kolekcji moĪna w áatwy sposób przesáaü z powro- tem do bazy danych. SáuĪy do tego metoda SubmitChanges obiektu DataContext. Tym samym wszelkie modyfikacje danych stają siĊ bardzo naturalne: nie ma koniecznoĞci przygotowywania poleceĔ SQL, odpowiedzialnych za aktualizacjĊ tabel w bazie da- nych — wszystkie operacje wykonujemy na obiektach C#. Zachowana jest w ten spo- sób spójnoĞü programu, co pozwala na kontrolĊ typów i peáną weryfikacjĊ kodu juĪ w trakcie kompilacji. Modyfikacje istniejñcych rekordów PokaĪmy to na prostym przykáadzie. ZaáóĪmy, Īe mija Nowy Rok i z tej okazji zwiĊk- szamy wartoĞü w polach Wiek wszystkich osób. Rzecz jasna wszystkich, poza kobie- tami, które są juĪ peánoletnie. Pobieramy zatem kolekcjĊ osób, które są mĊĪczyznami lub są niepeánoletnie. Spójnik „lub” uĪyty w poprzednim zdaniu rozumiany powinien byü tak, jak zdefiniowany jest operator logiczny OR — powinniĞmy uzyskaü sumĊ mno- goĞciową zbiorów osób niepeánoletnich i zbioru mĊĪczyzn. NastĊpnie zwiĊkszamy war- toĞü pola Wiek kaĪdej z osób tak uzyskanego zbioru. I najmilsza rzecz: aby zapisaü nowe wartoĞci do pliku bazy danych, wystarczy tylko wywoáaü metodĊ SubmitChanges na rzecz obiektu bazaDanychTelefony. PowyĪsze czynnoĞci ujĊte w jĊzyku C# prezentuje listing 3.3. Rozdziaä 3. i LINQ i SQL Server 33 Listing 3.3. Modyfikowanie istniejącego rekordu private void button2_Click(object sender, EventArgs e) { //pobieranie kolekcji var listaOsobDoZmianyWieku = from osoba in listaOsob where (osoba.Wiek 18 || !osoba.Imiú.EndsWith( a )) select osoba; //wyĞwietlanie pobranej kolekcji string s = Lista osób niebúdæcych peđnoletnimi kobietami: ; foreach (Osoba osoba in listaOsobDoZmianyWieku) s += osoba.Imiú + + ´osoba.Nazwisko + ( + osoba.Wiek + ) ; MessageBox.Show(s); //modyfikowanie kolekcji foreach (Osoba osoba in listaOsobDoZmianyWieku) osoba.Wiek++; //wyĞwietlanie peánej listy osób kolekcji po zmianie s = Lista wszystkich osób: ; foreach (Osoba osoba in listaOsob) s += osoba.Imiú + + osoba.Nazwisko + ( ´+ osoba.Wiek + ) ; MessageBox.Show(s); //zapisywanie zmian bazaDanychTelefony.SubmitChanges(); } Musi pojawiü siĊ pytanie, skąd obiekt bazaDanychTelefony (obiekt typu DataContext reprezentujący w naszej aplikacji bazĊ danych) wie o modyfikacjach wprowadzonych do kolekcji listaOsobDoZmianyWieku otrzymanej zapytaniem LINQ z kolekcji uzyskanej metodą bazaDanychTelefony.GetTable Osoba (). OtóĪ stąd, Īe kolekcja listaOsobDo ´ZmianyWieku przechowuje tylko referencje do obiektów tej tabeli, a nie kopie tych obiektów (por. zapytania LINQ w podrozdziale „MoĪliwoĞü modyfikacji danych Ĩró- dáa”, w rozdziale pierwszym). Zresztą w przypadku LINQ to SQL próba uruchomienia zapytania, w którym tworzymy kopie obiektów, skoĔczy siĊ zgáoszeniem wyjątku NotSupportedException. Tak wiĊc wszystkie zmiany wprowadzane do kolekcji wpro- wadzane są automatycznie w buforze obiektu bazaDanychTelefony, przechowującym dane pobrane z bazy danych. A obiekt ten juĪ potrafi zapisaü je z powrotem do tabeli SQL Server. Warto przy tym pamiĊtaü, Īe wszystkie zmiany wprowadzane w kolekcji są przechowywane tylko w niej aĪ do momentu wywoáania metody SubmitChanges. Mo- Īemy wiĊc dowolnie (wielokrotnie) modyfikowaü kolekcjĊ bez obawy, Īe naduĪywamy zasobów bazy danych i komputera, zmniejszając wydajnoĞü programu. W trakcie projektowania aplikacji naleĔy zwróciè uwagö, czy plik bazy danych widoczny w podoknie Solution Explorer jest kopiowany do katalogu, w którym umieszczana jest skompilowana aplikacja (podkatalog bin/Debug lub bin/Release). MoĔe to wprowadzaè pewne zamieszanie i utrudniaè Ĉledzenie zmian w bazie danych np. za pomocñ podokna Database Explorer. 34 C# 3.0 i .NET 3.5. Technologia LINQ Dodawanie i usuwanie rekordów Co jeszcze moĪemy zmieniü w tabeli? W zasadzie pozostaje tylko dodawanie nowych i usuwanie istniejących rekordów. RównieĪ to zadanie jest dziĊki LINQ to SQL bardzo proste. W tym przypadku zmiany muszą byü jednak wprowadzane wprost w obiekcie reprezentującym tabelĊ — instancji klasy DataContext, a nie w pobranej z niego ko- lekcji. Listing 3.4 pokazuje, jak dodaü do tabeli nowy rekord. Po utworzeniu obiektu DataContext (polecenia identyczne jak w poprzednich listingach) obliczamy wartoĞü pola Id dla nowego rekordu — do najwiĊkszej wartoĞci Id w tabeli dodajemy jeden4 — korzystamy przy tym z rozszerzenia Max. NastĊpnie tworzymy obiekt typu Osoba i poleceniem InsertOnSubmit dodajemy go do tabeli. Rzeczywista zmiana nastąpi w momencie najbliĪszego wywoáania metody SubmitChanges obiektu DataContext. Listing 3.4. Dodawanie rekordu do tabeli private void button3_Click(object sender, EventArgs e) { //dodawanie osoby do tabeli int noweId = listaOsob.Max(osoba = osoba.Id) + 1; MessageBox.Show( Nowe Id: + noweId); Osoba noworodek = new Osoba { Id = noweId, Imiú = Nela , Nazwisko = ´ Matulewska , NumerTelefonu = 0, Wiek = 0 }; listaOsob.InsertOnSubmit(noworodek); //zapisywanie zmian bazaDanychTelefony.SubmitChanges(); //dodawany jest takĪe nowy rekord //wyĞwietlanie tabeli string s = Lista osób: ; foreach (Osoba osoba in listaOsob) s += osoba.Imiú + + osoba.Nazwisko + ( ´+ osoba.Wiek + ) ; MessageBox.Show(s); } Równie áatwo usunąü z tabeli rekord lub ich grupĊ. NaleĪy tylko zdobyü referencjĊ do odpowiadającego im obiektu (wzglĊdnie grupy obiektów). W przypadku pojedyncze- go rekordu naleĪy uĪyü metody DeleteOnSubmit, w przypadku ich kolekcji — Delete ´AllOnSubmit. W obu przypadkach rekordy zostaną oznaczone jako przeznaczone do usuniĊcia i rzeczywiĞcie usuniĊte z bazy danych przy najbliĪszym wywoáaniu metody SubmitChanges. Listing 3.5 prezentuje metodĊ usuwającą z tabeli wszystkie osoby o imieniu Nela. Listing 3.5. Wszystkie modyfikacje w bazie danych wykonywane są w momencie wywoáania metody SubmitChanges private void button4_Click(object sender, EventArgs e) { //wybieranie elementów do usuniĊcia i ich oznaczanie IEnumerable Osoba doSkasowania = from osoba in listaOsob 4 WáaĞciwsze byáoby pewnie wyszukanie najmniejszej wolnej wartoĞci, ale nie chciaáem niepotrzebnie komplikowaü kodu. Zresztą zwykle tak postĊpujĊ, w myĞl zasady „prosty kod oznacza mniejsze ryzyko báĊdu”. Rozdziaä 3. i LINQ i SQL Server 35 where osoba.Imiú == Nela select osoba; listaOsob.DeleteAllOnSubmit(doSkasowania); //zapisywanie zmian bazaDanychTelefony.SubmitChanges(); //wyĞwietlanie tabeli string s = Lista osób: ; foreach (Osoba osoba in listaOsob) s += osoba.Imiú + + osoba.Nazwisko + ( ´+ osoba.Wiek + ) ; MessageBox.Show(s); } Klasa DataContext säuĔy nie tylko do pobierania i modyfikacji zawartoĈci bazy danych. Za pomocñ jej metod CreateDatabase i DeleteDatabase moĔna takĔe tworzyè i usu- waè bazy danych SQL Server z poziomu kodu. Za pomocñ metody ExecuteCommand moĔna wykonaè podane w argumencie polecenie SQL, a za pomocñ ExecuteQuery — uruchomiè zapytanie SQL i odczytaè pobrane przez nie dane. Wizualne projektowanie klasy encji W przypadku bardziej rozbudowanych baz danych najproĞciej klasĊ encji utworzyü, korzystając z wbudowanego w Visual Studio narzĊdzia, którego nazwa w dosáownym táumaczeniu to „projektant obiektowo-relacyjny” (ang. Object Relational Designer, w skrócie: O/R Designer) i który w istocie umoĪliwia automatyczne mapowanie struk- tury tabeli bazy danych w klasach C#. Nie chciaáem od niego rozpoczynaü omawiania LINQ to SQL, aby daü Czytelnikowi moĪliwoĞü poznania technologii „od podszewki”, tj. od wáasnorĊcznie przygotowanej klasy encji. Ale skoro juĪ taką klasĊ sami przy- gotowaliĞmy, nie musimy tego wiĊcej powtarzaü. Co prawda samodzielnie przygoto- wane klasy encji są zwykle bardziej zwarte, ale pisząc je, moĪemy popeániaü báĊdy, których unikniemy, tworząc klasy myszką. O/R Designer Zacznijmy od utworzenia klasy encji dla tabeli ListaOsob w bazie Telefony.mdf. W tym celu z menu Project wybieramy polecenie Add New Item. Pojawi siĊ okno widoczne na rysunku 3.1. Zaznaczamy w nim ikonĊ LINQ to SQL Classes. W polu Name poda- jemy nazwĊ nowego pliku: Telefomy.dbml. Po zamkniĊciu okna dialogowego zoba- czymy nową zakáadkĊ. Na razie pustą, nie licząc napisów informujących, Īe na dwa widoczne na niej panele naleĪy przenosiü elementy z podokna Database Explorer. PrzenieĞmy na lewy panel tabelĊ ListaOsob (rysunek 3.2). Konwencja nazw w pliku Telefony.dbml nie przystaje niestety do nazw, jakich uĪyáem w bazie Telefony.mdf. Auto- matycznie tworzona klasa encji przejmuje bowiem nazwĊ tabeli, tj. ListaOsob (nasza rĊcznie przygotowana klasa encji nazywaáa siĊ Osoba). Z kolei wáasnoĞü tylko do od- czytu zdefiniowana w klasie TelefonyDataContext, która zwraca tabelĊ (a konkretnie 36 C# 3.0 i .NET 3.5. Technologia LINQ Rysunek 3.1. Tworzenie klasy reprezentującej dane Rysunek 3.2. Zakáadka z O/R Designer kolekcjĊ typu Table ListaOsob ), nazywa siĊ ListaOsobs z „s” dodanym na koĔcu. Gdyby tabela nazywaáa siĊ np. Person, klasa encji nazywaáaby siĊ Person, a wáasnoĞü reprezentująca tabelĊ — Persons. Wówczas nazwy brzmiaáyby duĪo lepiej. A tak mamy ListaOsobs. Rozdziaä 3. i LINQ i SQL Server 37 Co prawda nazwy utworzonych przez O/R Designera klas moĪna áatwo zmieniü — wy- starczy na zakáadce Telefony.dbml kliknąü nagáówek tabeli (rysunek 3.2) i wpisaü nowe nazwy. To samo dotyczy nazw pól domyĞlnie ustalonych na identyczne jak znalezione w tabeli SQL Server. JeĪeli wpiszemy nazwĊ róĪną od tej w tabeli, O/R Designer zmo- dyfikuje atrybut Column, który wskaĪe pole tabeli, z jakim definiowane pole obiektu ma byü związane. Utworzona przez O/R Designer klasa ListaOsob (moĪna ją znaleĨü w pliku Telefony. ´designer.cs) jest klasą encji o identycznej funkcji jak zdefiniowana przez nas wczeĞniej klasa Osoba. Nie jest jednak z nią identyczna. TĊ pierwszą O/R Designer wyposaĪyá poza polami, które i my zdefiniowaliĞmy, równieĪ w zbiór metod i zdarzeĔ. Zawiaduje nimi O/R Designer i poza wyjątkowymi sytuacjami raczej nie naleĪy edytowaü ich kodu. Same pola, inaczej niĪ w naszej prostej implementacji, są w nowej klasie prywatne i poprzedzone znakiem podkreĞlenia. Zwróümy uwagĊ, Īe te z nich, które odpowiadają tym polom tabeli, które dopuszczają pustą wartoĞü, zdefiniowane zostaáy przy uĪyciu typu parametrycznego System.Nullable typ , gdzie typ to oryginalny typ danych .NET (w naszym przypadku int lub string). DostĊp do tych pól moĪliwy jest poprzez pu- bliczne wáasnoĞci. Przykáad takiej wáasnoĞci odpowiadającej polu Id widoczny jest na listingu 3.6. WáasnoĞü poprzedzona jest atrybutem Column, którego uĪywaliĞmy teĪ w naszej wczeĞniejszej klasie encji. Jej argumenty są jednak inne (poza IsPrimaryKey ustawionym na true). Ze wzglĊdu na identyczną nazwĊ pola tabeli i wáasnoĞci klasy argument Name zostaá tu pominiĊty. Dwa nowe argumenty to Storage, który wskazuje prywatne pole przechowujące wartoĞü komórki, oraz DbType. W tym ostatnim przecho- wywana jest informacja o oryginalnym typie pola tabeli (kolumny). Tworzy go nazwa typu dozwolona przez SQL Server (np. Int lub NVarChar(MAX)), uzupeániona ewentu- alnie frazą NOT NULL, jeĪeli baza nie dopuszcza pustych wartoĞci dla tego pola. Listing 3.6. WáasnoĞü Id klasy ListaOsob. Towarzyszy jej pole zdefiniowane jako private int _Id [Column(Storage= _Id , DbType= Int NOT NULL , IsPrimaryKey=true)] public int Id { get { return this._Id; } set { if ((this._Id != value)) { this.OnIdChanging(value); this.SendPropertyChanging(); this._Id = value; this.SendPropertyChanged( Id ); this.OnIdChanged(); } } 38 C# 3.0 i .NET 3.5. Technologia LINQ Wspomniana klasa reprezentująca caáą bazĊ danych zawiera wáasnoĞci odpowiadające tabelom bazy. Jest zatem, to modne ostatnio okreĞlenie, strongly typed. Pozwala dziĊki temu na bezpieczny, tj. zachowujący typy danych, dostĊp do zewnĊtrznego zasobu — do danych w bazie SQL Server. Nowe klasy TelefonyDataContext i ListaOsob moĪna wykorzystaü tak, jak robiliĞmy do tej pory z klasą Osoba i „rĊcznie” tworzoną instancją klasy DataContext. Listing 3.7 pokazuje kod metody, w której zmiany dotyczą w zasadzie wyáącznie nazw klas: z wcze- Ğniej uĪywanych DataContext i Osoba na TelefonyDataContext i ListaOsob. Skorzy- staáem takĪe z wáasnoĞci ListaOsobs (z „s” na koĔcu) pierwszej z klas, aby pobraü re- ferencjĊ do kolekcji zawierającej dane z tabeli ListaOsob (wyróĪnienie w listingu 3.7). Listing 3.7. Korzystanie z automatycznie utworzonej klasy encji do pobierania i modyfikacji danych z tabeli SQL Server private void button5_Click(object sender, EventArgs e) { //tworzenie obiektu DataContext i pobieranie danych z tabeli string nazwaPliku = Telefony.mdf ; nazwaPliku = Path.GetFullPath(nazwaPliku); if (!File.Exists(nazwaPliku)) { MessageBox.Show( Brak pliku + nazwaPliku); return; } TelefonyDataContext bazaDanychTelefony = new TelefonyDataContext(nazwaPliku); var listaOsob = bazaDanychTelefony.ListaOsobs; //pobieranie kolekcji var listaOsobPelnoletnich=from osoba in listaOsob where osoba.Wiek =18 select osoba; //wyĞwietlanie pobranej kolekcji string s = Lista osób peđnoletnich: ; foreach (ListaOsob osoba in listaOsobPelnoletnich) s += osoba.Imiú + + osoba.Nazwisko + ( + osoba.Wiek + ) ; MessageBox.Show(s); //informacje o pobranych danych MessageBox.Show( Typ: + listaOsobPelnoletnich.GetType().FullName); MessageBox.Show( Iloħè pobranych rekordów: + ´listaOsobPelnoletnich.Count().ToString()); MessageBox.Show( Suma wieku wybranych osób: ´+ listaOsobPelnoletnich.Sum(osoba = osoba.Wiek).ToString()); MessageBox.Show( Imiú pierwszej osoby: + listaOsobPelnoletnich.First().Imiú); s = Peđna lista osób: ; foreach (ListaOsob osoba in listaOsob) s += osoba.Imiú + + osoba.Nazwisko + ( + osoba.Wiek + ) ; MessageBox.Show(s); } Rozdziaä 3. i LINQ i SQL Server 39 Wspóäpraca z kontrolkami tworzñcymi interfejs aplikacji Ewidentnie naduĪywam metody MessageBox.Show. Bardziej naturalne do prezentacji danych jest oczywiĞcie korzystanie z kontrolek, np. DataGridView. Bez trudu moĪna taki komponent wypeániü danymi udostĊpnianymi przez klasĊ TelefonyDataContext. Dodajmy do projektu nową formĊ i zdefiniujmy w niej pole — instancjĊ tej ostatniej klasy: TelefonyDataContext bazaDanychTelefony = new TelefonyDataContext(); NastĊpnie wystarczy umieĞciü na formie kontrolkĊ DataGridView i przypisaü jej wáa- snoĞci DataSource odpowiednią tabelĊ (np. w konstruktorze za poleceniem Initialize ´Component();): dataGridView1.DataSource = bazaDanychTelefony.ListaOsobs; JeĪeli nie chcemy prezentowaü peánej zawartoĞci tabeli, wáasnoĞci DataSource moĪemy przypisaü kolekcjĊ zwracaną przez zapytanie LINQ: dataGridView1.DataSource = from osoba in bazaDanychTelefony.ListaOsobs where osoba.Wiek = 18 orderby osoba.Imiú select new { osoba.Imiú, osoba.Nazwisko, osoba.Wiek }; Kontrolka DataGridView pozwala na edycjĊ danych z kolekcji, jednak pod warunkiem, Īe prezentowana w niej kolekcja nie jest zbudowana z obiektów anonimowych typów, lecz z referencji do obiektów ze Ĩródáa danych (instancji klas encji): dataGridView1.DataSource = from osoba in bazaDanychTelefony.ListaOsobs where osoba.Wiek = 18 orderby osoba.Imiú select osoba; Aby wprowadzone w ten sposób modyfikacje danych wysáaü z powrotem do bazy, naleĪy tylko wywoáaü metodĊ SubmitChanges instancji klasy TelefonyDataContext, tj. obiektu bazaDanychTelefony. Do formy moĪemy dodaü takĪe rozwijaną listĊ ComboBox. MoĪemy „podáączyü” ją do tego samego wiązania, którym z bazą poáączona jest kontrolka dataGridView1. W tym celu do konstruktora naleĪy dopisaü dwa polecenia: comboBox1.DataSource = dataGridView1.DataSource; comboBox1.DisplayMember = Imiú ; Pierwsze wskazuje na Ĩródáo danych rozwijanej listy — jest nim ta sam kolekcja, która prezentowana jest w kontrolce dataGridView1. Drugie precyzuje, którą kolumnĊ da- nych rozwijana lista ma prezentowaü. Ze wzglĊdu na korzystanie ze wspólnego wią- zania zmiana aktywnego rekordu w siatce spowoduje zmianĊ rekordu w rozwijanej li- Ğcie i odwrotnie. 40 C# 3.0 i .NET 3.5. Technologia LINQ Kreator Ēródäa danych i automatyczne tworzenie interfejsu uĔytkownika Do utworzenia odpowiednich obiektów moĪna jednak ponownie zaprząc Visual C#. Oczy- wiĞcie, w takim przypadku kod nie bĊdzie tak prosty i przejrzysty jak ten napisany sa- modzielnie, ale za to nie musimy go przygotowywaü i sprawdzaü sami. Cel, do którego dąĪymy, to utworzenie Ĩródáa danych, takiego, do jakich przyzwyczaiáo nas ADO.NET. Jednak w tym przypadku czerpaü ono bĊdzie dane nie bezpoĞrednio z bazy danych, ale za pomocą LINQ to SQL, a wiĊc poprzez zaprojektowaną w O/R Designerze klasĊ TelefonyDataContext i towarzyszącą jej klasĊ encji. Dysponując takim Ĩródáem, bĊ- dziemy mogli wiązaü z danymi kontrolki, z których budujemy interfejs aplikacji. Wybierzmy z menu Data polecenie Add New Data Source…. Pojawi siĊ kreator Data Source Configuration Wizard. W jego pierwszym kroku wybieramy Ĩródáo danych (rysu- nek 3.3, górny); zaznaczmy ikonĊ Object. Klikamy Next . W nastĊpnym kroku wy- bieramy klasĊ, która zawiera informacje na temat struktury tabeli ListaOsob (rysunek 3.3, dolny). W naszym przypadku jest to klasa ListaOsob. Wreszcie klikamy Finish. Po zamkniĊciu kreatora wybierzmy polecenie Show Data Sources z menu Data. Pojawi siĊ nowe podokno o nazwie Data Sources, w którym zobaczymy nowe, utworzone przed chwilą Ĩródáo danych. MoĪemy sprawdziü jego pola — powinny odpowiadaü polom tabeli (rysunek 3.4). Tak zdefiniowane Ĩródáo danych nie zawiera niestety samych da- nych, a jedynie informacje o ich strukturze. To jednak wystarczy, aby bardzo przyspie- szyü projektowanie interfejsu uĪytkownika w aplikacjach bazodanowych. Gdy dysponujemy Ĩródáem danych, moĪemy zaprojektowaü interfejs aplikacji, korzy- stając z metody „przeciągnij i upuĞü”. MoĪemy bowiem przeciągaü na formĊ poszcze- gólne pola tabeli ListaOsob widoczne w podoknie Data Sources. Powstanie wówczas kontrolka z automatycznie dodanym opisem. Typ kontrolki, która powstanie, moĪna wczeĞniej wybraü w rozwijanych listach związanych z kaĪdym polem, w podoknie Data Sources (rysunek 3.4). Przeniesienie caáej tabeli spowoduje przy domyĞlnych usta- wieniach umieszczenie na formie siatki dataGridView. Jednak jeĪeli wczeĞniej w pozycji ListaOsob (w podoknie Data Sources) z rozwijanej listy wybierzemy Details zamiast domyĞlnego DataGridView, zamiast siatki na formie umieszczony zostanie zbiór kon- trolek zgodnie z wyborem dla kaĪdego z pól. Wraz z pierwszą umieszczoną w ten sposób kontrolką na formie pojawi siĊ komponent wiązania (listaOsobBindingSource) oraz kontrolka nawigacyjna (listaOsobBindingNavigator). TĊ ostatnią moĪemy zoba- czyü na szczycie podglądu formy na rysunku 3.4. Tak jak uprzedzaáem, Ĩródáo danych nie zawiera danych, a jedynie informacje o ich strukturze. Zatem po skompilowaniu kontrolki nie bĊdą prezentowaáy Īadnych sen- sownych informacji. Wystarczy jednak odpowiednio „podpiąü” kontrolkĊ wiązania listaOsobBindingSource, aby wszystko zaczĊáo graü. Zaczynamy od zdefiniowania pola formy bĊdącego instancją naszej klasy reprezentującej bazĊ danych: TelefonyDataContext bazaDanychTelefony = new TelefonyDataContext(); Rozdziaä 3. i LINQ i SQL Server 41 Rysunek 3.3. Pierwszy krok kreatora obiektu — Ĩródáa danych LINQ to SQL NastĊpnie w konstruktorze wiąĪemy udostĊpnianą przez ten obiekt tabelĊ ListaOsob z obiektem wiązania listaOsobBindingSource: listaOsobBindingSource.DataSource = bazaDanychTelefony.ListaOsobs; 42 C# 3.0 i .NET 3.5. Technologia LINQ Rysunek 3.4. Projektowanie interfejsu aplikacji na bazie Ĩródáa danych LINQ Wszystkie wizualne kontrolki tworzące interfejs uĪytkownika związane są z tym jed- nym obiektem wiązania, zatem zmiana aktualnego rekordu w którejkolwiek z nich spo- woduje automatyczną zmianĊ widocznego rekordu w pozostaáych. MoĪliwe jest oczy- wiĞcie zapisywanie zmian wprowadzonych za pomocą kontrolek. Wystarczy jedynie wywoáaü metodĊ bazaDanychTelefony.SubmitChanges. ãñczenie danych z dwóch tabel — operator join Informacje o osobach mogą byü umieszczone w kilku tabelach. Dla przykáadu w osob- nej tabeli mógáby byü umieszczony spis rozmów, jakie przeprowadzaáy osoby z tabeli ListaOsob. Tabela bĊdzie zawieraü identyfikator osoby, personalia jej rozmówcy, datĊ prze- prowadzenia rozmowy i jej czas trwania w minutach. Pola o nazwie Id i CzasTrwania bĊdą typu int, pole Rozmowca — typu nvarchar(MAX), a pole Data — typu datetime. ĩadne z pól nie bĊdzie dopuszczaü pustych wartoĞci. Kluczem gáównym moĪemy uczyniü tylko pole Data. Zapiszmy tabelĊ, nazywając ją po prostu Rozmowy. Pole Id w nowej tabeli bĊdzie tym samym Id, którym identyfikowana jest osoba w tabeli ListaOsob. Zatem kaĪdej osobie bĊdzie moĪna przyporządkowaü listĊ rozmów, a kaĪdej rozmowie — tylko jednego rozmówcĊ. Tabela ListaOsob bĊdzie wiĊc naszą tabelą-rodzicem, a ta- bela Rozmowy — tabelą-dzieckiem. TabelĊ naleĪy oczywiĞcie wypeániü jakimiĞ przy- káadowymi danymi (rysunek 3.5). NastĊpnie przejdĨmy na zakáadkĊ Telefony.dbml i przenieĞmy nową tabelĊ na lewy panel, obok tabeli ListaOsob. Do klasy TelefonyDataContext dodana zostanie nowa wáasnoĞü o nazwie Rozmowies (znowu nie dopasowaliĞmy siĊ do proangielskiego schematu nazw). Pobierzmy teraz listĊ rozmów trwających dáuĪej niĪ dziesiĊü minut wraz z persona- liami dzwoniącej osoby. W tym celu zapytanie LINQ rozszerzymy o operator join, który pobieraü bĊdzie rekordy o tych samych wartoĞciach pól Id w obu tabelach. Po- kazuje to listing 3.8. Rozdziaä 3. i LINQ i SQL Server 43 Rysunek 3.5. Nowa tabela bazy Telefony.mdf Listing 3.8. Pominąáem polecenia tworzące obiekt bazaDanychTelefony var listaOsob = bazaDanychTelefony.ListaOsobs; var rozmowy = bazaDanychTelefony.Rozmowies; IEnumerable string listaDlugichRozmow = from osoba in listaOsob join rozmowa in rozmowy on osoba.Id equals rozmowa.Id where rozmowa.CzasTrwania 10 select osoba.Imiú + + osoba.Nazwisko + , + rozmowa.Data.ToString() ´+ ( + rozmowa.CzasTrwania + ) ; string s = Lista rozmów trwajæcych dđuľej niľ 10 min: ; foreach (string opis in listaDlugichRozmow) s += opis + ; MessageBox.Show(s); Relacje (Associations) Zamiast korzystaü z operatora join, moĪemy poáączyü obie tabele w O/R Designerze. A w zasadzie nie tabele, tylko reprezentujące je klasy. PrzejdĨmy na zakáadkĊ Telefony. ´dbml, kliknijmy prawym przyciskiem myszy nagáówek tabeli ListaOsob i z kontek- stowego menu wybierzmy polecenie Add, Association. Pojawi siĊ edytor relacji (ry- sunek 3.6). Z rozwijanej listy Child Class wybieramy Rozmowy. NastĊpnie w tabeli Association Properties pod spodem wybieramy w obu kolumnach pole Id. 44 Rysunek 3.6. Edytor poáączenia miĊdzy obiektami reprezentującymi tabele C# 3.0 i .NET 3.5. Technologia LINQ Ustanowione poáączenie zaznaczone zostanie w O/R Designerze strzaáką áączącą dwie tabele. W podobny sposób zaznaczone byáyby relacje miĊdzy tabelami, które zdefi- niowane są w samej bazie danych. Skutek obu poáączeĔ jest podobny. DziĊki relacji áączącej obie tabele moĪemy uproĞciü zapytanie LINQ: var listaDlugichRozmow = from rozmowa in rozmowy where rozmowa.CzasTrwania 10 select rozmowa.ListaOsob.Imiú + + ´rozmowa.ListaOsob.Nazwisko + , + ´rozmowa.Data.ToString() + ´ ( + rozmowa.CzasTrwania + ) ; ; Jest to moĪliwe, poniewaĪ do klasy encji Rozmowy dodana zostaáa wáasnoĞü ListaOsob, która wskazuje na jeden pasujący rekord tabeli ListaOsob. Z kolei klasa encji ListaOsob zawiera wáasnoĞü Rozmowies obejmującą peáen zbiór rekordów, w których wartoĞü pola Id równa jest tej, jaka jest w bieĪącym wierszu tabeli ListaOsob. To ostatnie pozwala na proste filtrowanie danych bez koniecznoĞci przygotowywania zapytania LINQ. A wiĊc kolekcja uzyskana poleceniem: var listaRozmowKarolinyMatulewskiej = ´bazaDanychTelefony.ListaOsobs.Single(osoba = osoba.Id == 3).Rozmowies; zawiera identyczne rekordy jak uzyskana zapytaniem: var listaRozmowKarolinyMatulewskiej = from rozmowa in rozmowy where rozmowa.Id == 3 select rozmowa; Korzystanie z procedur skäadowanych W momencie uruchamiania metody SubmitChanges obiekt klasy DataContext automa- tycznie tworzy zbiór poleceĔ SQL, które modyfikują zawartoĞü bazy danych. Podob- nie jest zresztą w momencie pobierania danych. Wówczas zapytanie LINQ jest táuma- czone na zapytanie SQL i wysyáane do bazy danych. Rozdziaä 3. i LINQ i SQL Server 45 Zamiast korzystaü z tych tworzonych automatycznie procedur i zapytaĔ moĪemy wy- korzystaü wáasne procedury skáadowane w bazie danych (ang. stored procedures). Jest to w pewnym sensie krok wstecz, wymaga bowiem programowania w SQL, ale za to po- zwala na zachowanie peánej elastycznoĞci podczas korzystania z SQL Server. I nawet jeĪeli z procedur skáadowych nie bĊdziemy korzystaü do pobierania danych, warto je poznaü, aby móc uruchamiaü dowolne polecenia SQL, które pozwolą nam np. tworzyü nowe tabele w bazie. Pobieranie danych za pomocñ procedur skäadowanych Utwórzmy i zapiszmy w bazie danych zapytanie pobierające personalia osób peánoletnich zapisanych w tabeli ListaOsob. W tym celu otwórzmy plik Telefony.mdf w Database Explorer, przejdĨmy do pozycji Stored Procedures i prawym przyciskiem myszy roz- wiĔmy jej menu kontekstowe. Wybierzmy z niego polecenie Add New Stored Procedure. Pojawi siĊ edytor, w którym moĪemy wpisaü kod SQL (rysunek 3.7). Za sáowem kluczo- wym AS wpiszmy proste zapytanie SQL: SELECT * FROM ListaOsob WHERE Wiek =18. ZmieĔmy teĪ nazwĊ procedury na dbo.ListaOsobPelnoletnich. Wreszcie zapiszmy zmiany w bazie danych (Ctrl+S). W podoknie Database Explorer, w gaáĊzi Stored Procedures bazy Telefony.mdf, powinna pojawiü siĊ pozycja ListaOsobPelnoletnich. MoĪemy wów- czas przejĞü na zakáadkĊ Telefony.dbml i przeciągnąü procedurĊ z podokna Database Explorer do pustego panelu po prawej stronie. To spowoduje dodanie do klasy Telefony ´DataContext metody ListaOsobPelnoletnich. Zwraca ona dane pobrane przez za- pytanie SQL w postaci kolekcji elementów typu ListaOsobPelnoletnichResult. Rysunek 3.7. Edycja zapytania SQL procedury umieszczonej w bazie danych Typ ListaOsobPelnoletnichResult zostaá automatycznie utworzony za pomocą O/R Designera. W przypadku pobierania wszystkich pól z tabeli, tj. gdy w zapytaniu SQL po sáowie SELECT widoczna jest gwiazdka (*), nowa klasa bĊdzie równowaĪna typowi ListaOsob (i Osoba). Zapytanie SQL moĪe jednak zwracaü tylko wybrane pola, a wów- czas tworzenie nowego typu jest bardziej przydatne. 46 C# 3.0 i .NET 3.5. Technologia LINQ DziĊki nowej metodzie uruchomienie skáadowanego zapytania SQL i odebranie zwra- canych przez nie danych jest dziecinnie proste: IEnumerable ListaOsobPelnoletnichResult listaOsobPelnoletnich = ´bazaDanychTelefony.ListaOsobPelnoletnich(); Modyfikowanie danych za pomocñ procedur skäadowanych Przygotujmy teraz procedurĊ skáadowaną zwiĊkszającą o jeden wiek wszystkich osób niebĊdących peánoletnimi kobietami (listing 3.9). Zapiszmy ją w bazie pod nazwą AktualizujWiek i dodajmy do prawego panelu na zakáadce Telefony.dbml. Listing 3.9. Procedura skáadowana modyfikująca dane w tabeli ListaOsob ALTER PROCEDURE dbo.AktualizujWiek AS UPDATE ListaOsob SET Wiek=Wiek+1 WHERE NOT SUBSTRING(Imiú,LEN(Imiú),1)= a OR Wiek 18 RETURN Aby ją uruchomiü z poziomu C#, wystarczy do kodu dodaü instrukcjĊ: bazaDanychTelefony.AktualizujWiek(); Zmiany w tabeli bazy danych bĊdą wprowadzone natychmiast i bezpoĞrednio, tj. np. bez koniecznoĞci uruchamiania metody SubmitChanges instancji TelefonyDataContext. Z tego wynika teĪ, Īe jeĪeli wczeĞniej pobraliĞmy kolekcjĊ danych zapytaniem LINQ, naleĪy to teraz powtórzyü, aby uwzglĊdniü aktualizacje. Wykonywanie dowolnych poleceþ SQL Pobieranie danych i ich modyfikacja za pomocą skáadowanych poleceĔ SQL nie jest moĪe tym, co programiĞci znający LINQ zbytnio doceniają. Warto jednak zwróciü uwagĊ, Īe istnieje grupa czynnoĞci, które w SQL jest wykonaü najproĞciej. Przyjmijmy, Īe w naszej bazie danych tworzymy zbiór tabel dla kaĪdego nowego zarejestrowanego uĪytkownika. Wówczas nie do przecenienia jest moĪliwoĞü przygotowania skáadowanej procedury zawierającej kod SQL tworzący tabelĊ i wypeániający ją danymi. W tym celu wystarczy dodaü nową procedurĊ skáadową (przykáad widoczny jest na listingu 3.10), dodaü ją za pomocą O/R Designera do klasy TelefonyDataContext i wywoáaü w ko- dzie C#. NazwĊ i dane tabeli moĪemy przekazaü przez parametry procedury. PamiĊ- tajmy jednak, Īe nowa utworzona w ten sposób tabela nie bĊdzie zmapowana i w kon- sekwencji nie bĊdzie widoczna w obiekcie — instancji klasy TelefonyDataContext. Listing 3.10. Przykáadowa procedura skáadowa tworząca tabelĊ ALTER PROCEDURE dbo.TwórzNowæTabelú AS CREATE TABLE Faktury (Id INT, NrFaktury INT, Opis NVARCHAR(MAX)) INSERT INTO Faktury VALUES(1, 1022, Faktura za styczeē 2008 ) INSERT INTO Faktury VALUES(1, 1022, Faktura za luty 2008 ) RETURN
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

C# 3.0 i .NET 3.5. Technologia LINQ
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: