Jacek Matulewski c# 3.0 i .net 3.5. technologia linq full scan.pdf

(11007 KB) Pobierz
1257246475.001.png
4
C# 3.0 i .NET 3.5. Technologia LINQ
IQueryable<T> i IOrderedQueryable<T> ...................................................................... 69
Drzewo wyraenia .......................................................................................................... 71
Zadanie. LINQ to TXT ................................................................................................... 78
Dodatek A Wicej 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, 0ró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 0ród'a danych mo%e odby& si# dopiero w trakcie dzia'ania programu.
Realizowane jest to za pomoc drzewa zapyta1, które poznamy dok'adniej w ostatnim
rozdziale, przy okazji projektowania w'asnego 0ró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 znale0& si# powinien atrybut Table z przestrzeni nazw System.Data.
Linq.Mapping , w którym wskazujemy nazw# tabeli z bazy danych 1 . 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 zwi1zana z tabel1 ListaOsob z bazy Telefony.mdf
[Table(Name = "ListaOsob")]
public class Osoba
{
[Column(Name = "Id", IsPrimaryKey = true)]
public int Id;
[Column(Name = "Imi2", 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 'a1cuchó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> .
1257246475.002.png
Rozdzia! 3. 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 78 informatyki, ale nie chcia bym snu; dygresji na jej temat.
Osoby zainteresowane teori7 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
nazw System.Data.Linq , nale%y wi#c uwzgl#dni& j w grupie polece1 using 3 . Ostat-
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 pomoc1 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 ).
1257246475.003.png 1257246475.004.png
Zgłoś jeśli naruszono regulamin