Leszek Stasiak Zastosowanie technologii LINQ w C#
1. Wstęp - połączenie Do naszych zadań będziemy używać Microsoft Visual Studio 2010. Stwórzmy nowy projekt Windows Form Application. Mając do dyspozycji bazę danych northwind zapisaną w pliku, klikamy View->Server Explorer. Po lewej stronie zobaczymy okno. Klikamy trzecią kontrolkę Connect to Database, po czym wybieramy nasz plik z bazą danych. Po wybraniu odpowiedniego pliku zobaczymy widok bazy danych (Rys.1) Rys. 1 Następnie dodamy nową klasę do naszego projektu. W prawym oknie (Solution Explorer) klikamy prawym przyciskiem w katalog główny naszego projektu i wybieramy Add->New Item Tam wybieramy LINQ to SQL Classes. Po utworzeniu nowej klasy zobaczymy nowe okno. Tam właśnie możemy przeciągnąć naszą tabelę z okna bazy (Rys.1). Ja przeciągnąłem tabelę Products i nią będę się na początku posługiwał. Po przeciągnięciu tabela jest gotowa do pracy. Uwaga!!! Jeśli pierwszy raz przeciągamy tabelę do klasy LINQ pojawi się komunikat, który informuje o konieczności modyfikacji programu. Kliknijmy TAK. 2. Najprostsze zapytanie Zanim zaczniemy pobierać informację z bazy danych, stwórzmy twoję obiektów w klasie głównej programu. Przede wszystkim utwórzmy obiekt klasy DataGridView i nazwijmy go DgvView, oraz jeden Button z nazwą btest1 oraz wartością Test1. Aby nie tworzyć za każdym razem nowego obiektu DataClasses1DataContext utwórzmy go na początku klasy. KOD C# - 1 public partial class Form1 : Form DataClasses1DataContext dc = new DataClasses1DataContext(); public Form1() InitializeComponent();
Teraz klikamy dwukrotnie na button Test2, aby nadać mu akcję. W powstałej funkcji wpisujemy : KOD C# - 2 private void btest1_click(object sender, EventArgs e) var query = from c in dc.products select c; Test 1 Kiedy uruchomimy i klikniemy na przycisk Test1 w naszym DataGridView wyświetli się cała zawartość naszej tabeli. No dobrze A jeśli chciałbym wyświetlić tylko dwie kolumny? Znając jeżyk SQL domyślamy że że wystarczy dać: KOD C# - 3 var query = from c in dc.products select c.productid, c.productname; Niestety to nie działa. Już po chwili zauważamy że kompilator rzuca w nas błędami. Jednakże możemy poradzić sobie inaczej. Oto przykład kodu KOD C# - 4 private void btest2_click(object sender, EventArgs e) var query = from c in dc.products select newc.productid,c.productname; Test 2 Dodatkowo możemy także tutaj zmienić nazwy kolumn używając: KOD C# - 5 var query = from c in dc.products select newid=c.productid,c.productname; Po uruchomieniu programu zobaczymy dwie kolumny, z których pierwsza będzie miała nagłówek ID. Myślimy sobie teraz, jak to ładnie wygląda i prosto się obsługuje. Tylko, że te wyniki są jakieś niepoukładane. Znowu przypominamy sobie o poczciwym SQL. Może dać tak order by c.productid? No prawie byśmy trafili. Jednakże pierwsze dwa słowa piszemy razem. KOD C# - 6 private void btest3_click(object sender, EventArgs e) var query = from c in dc.products orderby c.productid select new c.productid, c.productname ; Test 3
OOO Działa!!! Ale ja jestem wybredny. Chcę sortowania od największej do najmniejszej. Wystarczy napisać descending: KOD C# - 7 var query = from c in dc.products orderby c.productid descending select new c.productid, c.productname ; Trochę dużo tych wyników Może trzeba pomyśleć aby je ograniczyć, aby znaleźć to co nas interesuje. Może wyświetlmy na początek rekordy o ProductID<10, dodając składnię where KOD C# - 8 private void btest4_click(object sender, EventArgs e) var query = from c in dc.products where c.productid<10 orderby c.productid select new c.productid, c.productname ; Test 4 A gdyby były dwa warunki? Możemy powtórzyć składnię where KOD C# - 9 var query = from c in dc.products where c.productid < 10 where c.productname.substring(0,1) == "C" orderby c.productid select new c.productid, c.productname ; Można też to połączyć używająć dwóch ampersandów. KOD C# - 10 var query = from c in dc.products where c.productid < 10 && c.productname.substring(0,1) == "C" orderby c.productid select new c.productid, c.productname ; Drugi warunek sprawdza czy pierwszy znak pola jest równy C. Zaletą LINQ jest to że odwołujemy się do tego pola jak do stringów, tzn. że działają wszystkie funkcje stringowe.
3. Coś więcej W tabeli Product mamy kolumnę o nazwie CategoryID. Jednakże jeśli widzimy tylko liczbę nic nam to nie daje (Test 1). Patrzymy teraz do tabeli Category (Server Explorer). Mamy tam m.in. CategoryID oraz CategoryName. Aha Chciałbym aby w tabeli to CategoryName wyświetlało się zamiast tego CategoryID. Nic trudnego Musimy jednakże wrócić do naszego okna DataClasses1.dbml, tego które było białe na początku. Przeciągamy teraz tam naszą tabelę Category. Po przeciągnięciu widzimy że dwie tabele połączyły się węzłem, tzn. że mają element wiążący. W tym przypadku jest to CategoryID (Rys. 2). Kierunek strzałki znaczy która tabela dostarcza danych do drugiej tabeli. Rys. 2 Jeśli to zrobiliśmy możemy teraz wrócić do naszego programu. Wystarczy że odwołamy się teraz do naszej kolumny z tabeli Category. KOD C# - 11 private void btest5_click(object sender, EventArgs e) var query = from c in dc.products orderby c.productid select new c.productid, c.productname, c.category.categoryname ; Test 5 Widzimy że odwołujemy się do tej kolumny tak jakby należałą do tej tabeli, jednakże musimy na początku wskazać nazwę tabeli z której na kolumna pochodzi. Powiązanie między tabelami jest automatyczne. Teraz ubzdurałem sobie aby te wyniki przechować w tablicy. KOD C# - 12 private void btest6_click(object sender, EventArgs e) var query = (from c in dc.products orderby c.productid select new c.productid, c.productname, c.category.categoryname ).ToArray(); MessageBox.Show(query[0].ToString()); Test 6 Kod napisany powyżej spowoduje wyświetlenie pierwszego wyniku z poprzedniego polecenia. Jak widzimy wynik przechowywany jest w tablicach.
Tak sobie siedzę i myśle Ile rekordów ma moja tabela Product? Niby można wziąć ostatni rekord z tabeli. Ale jeśli usunęliśmy jakiś rekord, wtedy nie pokaze nam poprawnej wartości. Użyjmy więc funkcji Count() KOD C# - 13 private void btest7_click(object sender, EventArgs e) int query = (from c in dc.products select c).count(); MessageBox.Show(query.ToString()); Test 7 Po kliknięciu na przycisk w okienku zobaczymy liczbę rekordów tabeli Product.