E N D
Language Integrated Query (LINQ) • LINQ je komponenta .NET Framework-a 3.5 ipredstavlja Microsoft-ovodgovorna gap (jaz) između OOP paradigme (principa programiranja) i organizacije i manipulacije podacima u relacionim modelima podataka (relacionim bazama podataka – DBMS-ovima koji koriste relacioni model) • Relacioni model je arhaičan i datira još iz ranih 70’tihgodina (Edgar Frank Codd), dok je objektni model – paradigma u principudostamlađi, iako OOP takođe vuče korene postojanja još iz kasnih60’tih(Simula 67 koja je uvelanizveomavažnih OOP koncepata – uticala na nastanak C++-a po rečima Bjorn Stoustrup-a, tvorca C++-a)
Language Integrated Query (LINQ) • Relacioni model podataka i SQL (Structured Query Language) jezik je još uvek neprikosnoveni standard za baze podataka, dok su se programski jezici u međuvremenu daleko više transformisali i evoluirali u smeru OOP-a i olakšavanja rada programera i podizanja efikasnosti razvoja programa • Relacioni model i SQL jezik su kao standard daleko manje menjani i prilagođavani, tako da danas imamo situaciju da savremeni programski jezici kao C# i JAVA koriste arhaični relacioni model podataka i SQL jezik
Language Integrated Query (LINQ) • LINQ se koristi za rad sa podacima koji mogu da budu organizovani na razne načine – u kolekcijama, XML-u, relacionim bazama – SQL-u. • Ovde će biti razmotrena primena LINQ-a na kolekcije • Kao primer će služiti dve kolekcije podataka o kupcima – Customers i o adresama – Addresses
Ove dve kolekcije podataka predstavljaju malu bazu podataka u RAM memoriji računara na kojoj će biti prikazane neke od mogućnosti LINQ-a
Language Integrated Query (LINQ) • Za demonstriranje LINQ-a sa kolekcijama, neophodno je da kolekcija implementira IEnumerableinterface, pri čemu sam tip kolekcije nije bitan – to može biti array, HashTable, Queue ili korisnička kolekcija, bitno je da je enumerable. • Customers and Addresses kolekcije podataka su implicitno definisani nizovi neimenovanih objekata • var customers = new[] { • new { CustomerID = 1, FirstName = “Orlando”, LastName = “Gee”, • CompanyName = “A Bike Store” }, • new { CustomerID = 2, FirstName = “Keith”, LastName = “Harris”, • CompanyName = “Bike World” }, ... itd
Language Integrated Query (LINQ) • var addresses = new[] { • new { CompanyName = “A Bike Store”, City = “New York”, Country = “United States”}, • new { CompanyName = “Bike World”, City = “Chicago”, Country = “United States”}, ... Itd
Selekcija podataka • IEnumerable<string> customerFirstNames = • customers.Select(cust => cust.FirstName); • foreach (string name in customerFirstNames) • { • Console.WriteLine(name); • } • Select je statički extension metod klase Enumerable iz System.Linq imenskog prostora • Klasa Enumerable implementira i razne druge metode koji se koriste u LINQ-u • Cust je bilo koji identifikator u C#-u
Selekcija podataka • Select metod generiše kolekciju – niz koji je enumerable i koji sadrži imena iz customers niza. • Do tih imena se dolazi prolaskom kroz kolekciju for each petljom • Šta ako je potrebno da se sa Select izdvoji više podataka, a ne samo jedan – ime, na pr. ime i prezime? • Deklaracija Enumerable.SelectmetodauSystem.Linq: • public static IEnumerable<TResult> Select<TSource, TResult> ( • IEnumerable<TSource> source, • Func<TSource, TResult> selector)
Select metod klase Enumerable • Select je statičkigenerički metodkoji uzima dva tipa parametara – TSource i TResult. TSource je tip elemenata kolekcije iz koje se uzimaju podaci (customers – niz neimenovanih objekata), dok je TResult tip elemenata kolekcije koja je rezultat – koju vraća metod Select, String. • Func je generički delegat koji takođe koristi iste tipove TSource i TResult • Umesto ili kao delegat Func koristi se λ izraz kojim se na jednostavan način predstavlja argument metoda Select, jer ovaj metod očekuje funkciju kao argument – delegat je pokazivač na metod - funkciju
Mogućnosti za vraćanje više podataka • Više podataka tipa String se može konkatenirati – nadovezati i vratiti kao jedan String podatak • IEnumerable<string> customerFullName = • customers.Select(cust => cust.FirstName + " " + cust.LastName); • Može se i definisati nova klasa koja ima više podataka • class Names • { • public string FirstName{ get; set; } • public string LastName{ get; set; } • } • ... • IEnumerable<Names> customerName = • customers.Select(cust => new Names { FirstName = cust.FirstName, • LastName = cust.LastName } );
Vraćanje više podataka • Umesto kreiranja nove klase – strukture samo za vraćanje više podataka, mogu se u tu svrhu kreirati bezimeni objekti – za vraćanje više podataka • var customerName = • customers.Select(cust => new { FirstName = cust.FirstName, LastName = cust.LastName } ); • Metod Select omogućava da se selektuju – navedu, specificiraju ili projektuju polja ulazne kolekcije koja će se vratiti – uključiti u izlaznu kolekciju
Filtriranje podataka • Filtriranjem podataka se biraju elementi ulazne kolekcije koji će se uvrstiti u izlaznu kolekciju, za šta se koristi metod Where • IEnumerable<string> usCompanies = • addresses.Where(addr => String.Equals(addr.Country, “United States”)) • .Select(usComp => usComp.CompanyName); • foreach (string name in usCompanies) • { • Console.WriteLine(name); • }
Metod Where • Sintaksa metoda Where je slična sintaksi metoda Select. • Metod Where očekuje argument koji je delegat na metod koji definiše filtriranje – izdvajanje elemenata ulazne kolekcije koji će se vratiti • Umesto delegata može se koristiti i λ izraz • Argument addr λ izraza predstavlja jedan elemenat ulazne kolekcije • λ izraz selektuje samo one elemente kod kojih podatak Country elementa kolekcije ima vrednost “United States” tipa String
Metod Where • Metod Where vraća enumerable kolekciju koja je deo ulazne kolekcije sa elementima koje vraća λ izraz • Na tu izlaznu kolekciju se može primeniti Select metod za odabir polja elemenata izlazne kolekcije koji će se vratiti • Rezultujuća enumerable izlazna kolekcija koja se dobija uzastopnim delovanjem metoda Where pa onda Select se može pregledati preko for each konstrukcije
Sortiranje elemenata kolekcije • Metodi Select i Where u LINQ-u su analogni nazivima i funkciji odgovarajućih SQL klauzula • Za sortiranje elemenata koje se jednostavno postiže u SQL-u sa group by klauzulom, u LINQ-u postoji GroupBy metod • Kao i prethodno pomenuti metodi – Select i Where, GroupBy metod takođe očekuje argument tipa delegata koji vraća polje elemenata kolekcije prema kome se vrši uzlazno sortiranje • Za silazno sortiranje se koristi metod OrderByDescending, analogno metodu OrderBy • Ako je potrebno sortiranje po više polja, za sortiranje po prvom polju se koristi OrderBy, a po svakom sledećem metod ThenBy ili ThenByDescending
Sortiranje elemenata kolekcije • IEnumerable<string> companyNames = • addresses.OrderBy(addr => addr.CompanyName).Select(comp => comp.CompanyName); • foreach (string name in companyNames) • { • Console.WriteLine(name); • } • λ izraz argument metoda OrderBy vraća polje CompanyName po kome se vrši sortiranje ulazne kolekcije
Grupisanje elemenata kolekcije • Za grupisanje podataka prema jednom ili više polja koristi se metod GroupBy • var companiesGroupedByCountry = • addresses.GroupBy(addrs => addrs.Country); • foreach (var companiesPerCountry in companiesGroupedByCountry) • { • Console.WriteLine(“Country: {0}\t{1} companies”, • companiesPerCountry.Key, companiesPerCountry.Count()); • foreach (var companies in companiesPerCountry) • { • Console.WriteLine(“\t{0}”, companies.CompanyName); • } • }
Metod GroupBy • Metod argument metoda GroupBy vraća polje po kome se vrši grupisanje elemenata ulazne kolekcije, tako da metod GroupBy u vraća kolekciju grupisanih enumerable elemenata, tako da grupisani elementi takođe sačinjavaju enumerable kolekciju. • Iz tog razloga se za prikaz – obilazak svih elemenata izlazne kolekcije dobijene sa GroupBy, koriste dve koncentrične for each konstrukcije, jedna za prolazak kroz kolekciju čiji su elementi kolekcije grupisanih elemenata, a druga za prolazak kroz svaki element koji predstavlja kolekciju grupisanih elemenata po datom polju koje vraća metod argument
Rezultat GroupBy metoda • Country: United States 2 companies • A Bike Store • Bike World • Country: Canada 1 companies • Fitness Hotel • Country: United Kingdom 2 companies • Grand Industries • Distant Inn
Agregatni – summary metodi • Analogno agregatnim funkcijama u SQL-u koje služe za izračunavanje jedne vrednosti za čitavu grupu podataka – max, min, sum, avg, count, ... i u LINQ-u takođe postoje odgovarajući metodi kao na pr. Count koji se koristi za izračunavanje broja grupisanih elemenata u kolekciji • Za razliku od prethodnih metoda, summary metodi ne vraćaju kolekciju, već samo jednu vrednost tipa Int koja predstavlja broj odgovarajućih elemenata kolekcije
Prebrojavanje različitih elemenata • Ako se želi prebrojavanje samo različitih elemenata, koristi se metod Distinct, analogno klauzuli distinct u SQL-u • int numberOfCountries = • addresses.Select(addr => addr.Country).Distinct().Count();
Spajanje podataka • Analogno SQL-u, LINQ omogućava da se spajaju dve ili više kolekcija podataka preko zajedničkih polja elemenata kolekcije • var citiesAndCustomers = customers • .Select(c => new { c.FirstName, c.LastName, c.CompanyName }) • .Join(addresses, custs => custs.CompanyName, addrs => addrs.CompanyName, • (custs, addrs) => new {custs.FirstName, custs.LastName, addrs.Country }); • foreach (var row in citiesAndCustomers) • { • Console.WriteLine(row); • } • Zajedničko polje u kolekcijama customers i addresses koje se koristi za spajanje je CompanyName
Postupak i sintaksa spajanja – join u LINQ-u • Join metod ima sledeće parametre: • Enumerable kolekciju (addresses) sa kojom se spaja kolekcija kojoj pripada metod Join (projekcija customers - custs dobijena sa Select) • Delegat za metod koji vraća zajednička polja kolekcije (custs) dobijene sa Select • Delegat za metod koji vraća zajednička polja kolekcije (addresses) koja se spaja • Delegat za metod koji vraća polja u rezultujućoj kolekciji koja nastaje spajanjem sa Join
Razlika u odnosu na podatke u bazi • Podaci u memoriji – kolekcijama se razlikuju od podataka u tabelama relacione baze podataka po slabijem integritetu podata u memoriji • Na primer, nije garantovan referencijalni integritet podataka, tj. u kolekciji custs može postojati kupac sa imenom firme koja ne postoji u drugoj kolekciji addresses • Moguće je i da se isto ime kompanije ponavlja u kolekciji addesses
Query operatori • Do sada korišćeni extension metodi klase Enumerable iz System.Linq prostora imaju sintaksu koja nije elegentna i njihovo korišćenje proizvodi kod koji takođe nije elegantan i ne liči na uobičajenu SQL sintaksu, iako je kod po smislu ekvivalentan SQL-u • Umesto koda: • IEnumerable<string> customerFirstNames = • customers.Select(cust => cust.FirstName); • mogu se upotrebiti from i select query operatori • var customerFirstNames = from cust in customers • select cust.FirstName;
Query operatori • Korišćenje from i select operatora daje kod koji više liči na SQL sintaksu • Ipak, značajna razlika je u suprotnom redosledu from i select u odnosu na SQL – prvo ide select pa posle from • var customerNames = from c in customers • select new { c.FirstName, c.LastName }; • var usCompanies = from a in addresses • where String.Equals(a.Country, “United States”) • select a.CompanyName;
Query operatori • var companyNames = from a in addresses • orderby a.CompanyName • select a.CompanyName; • var companiesGroupedByCountry = from a in addresses • group a by a.Country; • foreach (var companiesPerCountry in companiesGroupedByCountry) • { • Console.WriteLine(“Country: {0}\t{1} companies”, • companiesPerCountry.Key, companiesPerCountry.Count()); • foreach (var companies in companiesPerCountry) • { • Console.WriteLine(“\t{0}”, companies.CompanyName); • } • }
Query operatori • int numberOfCompanies = (from a in addresses • select a.CompanyName).Count(); • int numberOfCountries = (from a in addresses • select a.Country).Distinct().Count(); • int numberOfCompanies = addresses.Count(); • var citiesAndCustomers = from a in addresses • join c in customers • on a.CompanyName equals c.CompanyName • select new { c.FirstName, c.LastName, a.Country };
Odložena evaluacija u LINQ-u • Kada se pomoću LINQ-a dobijaju enumerable kolekcije, te kolekcije se ne kreiraju kada se izvrše LINQ extension metodi ili query operatori, već kada se prolazi kroz elemente kolekcije sa for each konstrukcijom • To znači da podaci u ulaznoj kolekciji mogu da se promene između izvršavanja LINQ upita i prolaska kroz elemente rezultujuće kolekcije, tako da će se dobiti rezultat u saglasnosti sa najnovijom verzijom podataka • Sa ToList metodom, može se forsirati kreiranje kopije rezultujuće kolekcije čim se izvrši LINQ upit
Odloženo izvršavanje: • var usCompanies = from a in addresses • where String.Equals(a.Country, “United States”) • select a.CompanyName • foreach (string name in usCompanies) • { • Console.WriteLine(name); • } • Forsirano izvršavanje: • var usCompanies = from a in addresses.ToList() • where String.Equals(a.Country, “United States”) • select a.CompanyName;