Blog Archives

LINQ- VII LINQ TO SQL


…nastavak prethodnog posta

Posebne napomene uz LINQ to SQL dizajner

LINQ to SQL je jednostavni O/R dizajner i podržava mapiranje 1:1. To znači da dizajner mapira jednu klasu (entitet) i samo jednu Tabelu ili View. Složeno mapiranje objekata, poput mapiranja klasa i spojenih tabela nije za sada podržano. LINQ to SQL dizajner jednostrano generira kod. Ako napravimo ručne promjene u izvornom kodu to se neće reflektirati na dizajner. Samo promjene napravljene preko dizajnera u dizajnerskom modu reflektuju se u izvorni kod.

Modifikacija podataka sa LINQ To SQL

U dosadašnjim primjerima vidjeli smo kako uzvući podatke iz DB, koristeći LINQ to SQL. Takodjer, vidjeli smo kako izvlačiti podatke iz relacijski-povezanih tabela. U ovom dijelu vidjećemo na koji nači vršimo modifikaciju podataka. Modifikacija podataka se odvija preko klase DataContext.

Klasa DataContext

DataContext je centranla klasa koja upravlja svim transakcijama koje se dešavaju. Ova klasa je odgovorna za pristup Serveru DB, prosljedjivanju SQL upita, monitoring nad modificiranim podacima na klijentu (ObjectTracking), rješavanju konflikata kod slanja podataka na Server i mnogo više. Kada pogledamo izvorni kod koji je dizajner generirao za ovu klasi nećemo naći puno toga. Ona se uglavnom sastoji od nekoliko konstruktora preko kojih instanciramo objekat , te članove (fields) koji su entiteti modela. Ova klasa se u pravilu uvijek koristi kao izvedena jer tim načinom dobijamo tipizirani (strongly typed) DataContext.

Metode koje sadržava ova klasa možemo podijeliti na sljedeće:

· Metoda za manipulaciju sa DB

· Metode za izvršavanje upita

· SubmitChanges() – metoda za slanje podataka u DB

· Opcije za rješavanje konflikata prilikom slanja podataka u DB

· Transakcije

SabmitChanges()

Prilikom bilo kakvih promjena podataka na klijentu klasa DataContext sadrži mehanizam praćenja svih tih promjena. Ovaj mehanizam se zove CHANGE PROCESSOR, i zadužen je za praćenje promjena podataka na klijentu. Kada pozovemo SubmitChanges(), klasa DataContex će pokušati pretvoriti sve promjene u adekvatne upite i prosljediti SQL Serveru. Prilikom generiranja upita DataContext će na osnovu generiranog DB modela uvažavajući sve relacije izmedju klasa i sva ograničenja kolona te primarne i vanjske ključeve, generirati SQL upite, koji će sekvencijalno slati na server. Prije samog slanja formira se transakcija koja se prekida i vraća u prvobitno stanje podatke, ako najmanje jedan upit bude neuspješan. Tada se izbacuje izuzetak i upozorava korisnik da promjene nisu uspješno prosljeđene Serveru.

Obzirom da transakcija nije prošla, DataContext ima sve informacije o upitima koji stvaraju konflik. Na taj način obezbjeđeno je pozivanje ove metode više *** sa korekcijama konflikata. Kada poslije korigiranja promjena, metoda uspije bez izuzetaka DataContext se resetuje i iz početka prati novonastale promjena na klijetu. Više informacija oko ove metode i klase možete naći na kraju ovog članka u referencama. Slanje podataka na server i način na koji se to odigrava zavisi od osobina (properties) svake klase u modelu, koje su prethodno prikazane. Naredni primjer pokazaće način na koji manipulišemo podacima iz DB, odnosno korištenje standardnih SQL naredbi Select, Insert, Update, Delete ili jednostavno CRUD.

Primjer sa sastoji od modela NorthWind baze podataka. Ako je ne posjedujete možete je skinuti sa ovog linka.

1. Formirajte novi projekat u VS 2008, C# programskijezik, Windows Forms Application tip projekta. Slično prethodnim primjerima

2. Formirajte LINQ to SQL dbml model baze podataka, te mapirajte tabele kao na slici.

clip_image002

3. Otvorite cs datoteku Form1, te iz usidrenog prozora DataSource importujete prethodne tabele kao objekte. Nakon importovanja DataSource prozor izgleda kao na slici.

clip_image004

4. Povucite i spustite Tabelu Order, a iz njenog drveta povucite i spstite tabelu Order_Detail. Rezultat bi trebao da izgleda kao na sljedećoj slici:

clip_image006

5. Implementirajte dogadjaj FormLoad, te privatni član klase Form1, dcNorthWind klase NorthWindKlaseDataContext.

6. Napišite implementaciju dogadjaja kao na sljedećoj slici.

clip_image008

Obzirom da smo LINQ to SQL modelom definisali i relacije izmedju klasa, nije potrebno posebno implementirati upite za svaku tabelu. Dovoljo je implementirati upit za tabelu Order, a kako smo vidjeli u prethodnom primjeru (prethodni post), podaci za ostale tabele se generiraju iz tabele Order.

7. Pokrenite aplikaciju. Rezultat bi trebao da izgleda kao na sljedećoj slici.

clip_image010

Pomjerajući se kroz tabelu Order, relevantni podaci u tabeli Order_Details se pojavljuju, odnosno implementacija relacije Master/Detail je realizirana.

Modifikacija podataka

Da bi mogli modificirati podatke u tabelama potrebno je da se implementira opcija Save (neaktivna sličica i navigacijskog toolbara clip_image012). Da bi implementirali spremanje podataka u DB, dva *** kliknimo na prethodno dugme i implementirajno metodu kao na sljedećoj slici, te osobinu Enable stavimo na TRUE. Bez obzira kako kompleksna forma bila, metodom SubmitChange(), LIN to SQL pohranjuje kako jednostavne tako i kompleksne hiearhijske zapise u bazu.

clip_image014

clip_image016

Prethodni primjer unosa novih stavki u relaciju Master/Detail prezentira svu jačinu LINQ to SQL tehnologije. Za ovakav primjer bilo nam je potrebno puno više vremena i živaca, koristeći DataSet ili DataTable.

LINQ TO SQL i Storne Procedure

Jednostavnost i ušteda na implementaciji koju smo vidjeli u prethodnom primjeru ništa nije drugačija i kompleksnija i kod korištenja stornih procedura. Storne procedure kao što smo vidjeli mapiraju se u desni dio prozora dizajnera, povlačeći i spuštajući stornu proceduru iz baze podataka.

Sljedeći primjer pokazuje korištenje stornih procedura sa LIN to SQL. U prethodni primjer mapirajmo stornu prceduru kao na slici.

clip_image018

Implementirajmo novu formu SPForm2, te njen dogadjaj FormLoad, kao na slici. U Početnoj formi implementirajte Dugme Pozivanje SP, te dogadjaj ButtonClick.

clip_image020

Implementacija Dugmeta Pozivanje SP, izgleda kao na sljedećoj slici:

clip_image022

Kompajlirajete i pokreite aplikaciju, nakon klika na dugme Pozivanje SP, pojavljuje se prozor sličan kao na slici:

clip_image024

Izvorni kod za ovaj post možete skinuti odavde.

Reference:

1. http://msdn2.microsoft.com/en-us/vcsharp/aa336746.aspx

2. http://weblogs.asp.net/scottgu/

3. http://blogs.msdn.com/somasegar/

4. http://channel9.msdn.com

5. http://aspalliance.com/1331_Using_LINQ_to_SQL__Part_2.all

LINQ – VI DIO LINQ TO SQL


…nastavak prethodnog posta

DB Model

Nakon uspješno izvedenog tutorijala pokušat ću objasniti način na koji radi LINQ to SQL.

Prva stvar koji smo uradili bila je formiranje modela DB. Procedura se ništa ne razlikuje od one kojom formiramo novu formu ili neku kontrolu. Kada smo formirali LINQ to SQL datoteku, VS dizajner je prikazao prazan model, koji se sastoji od dva podjeljena prozora lijevi prozor u kojem modeliramo klase odnosno entitete, a u drugi desni importujemo funkcije i storne procedure. Funkcija modela baze podataka je mapiranje prvenstveno tabela iz DB, koje u .NET nazivamo klasama ili entitetima. Svaki entitet je mapirana tabela, čije osobine (Properties) mapiraju kolone iz dotične tabele. I na kraju svaka instanca klase je jedan red (vrsta) tabele DB-a.

lintosql15

Razlika izmedju dizajnera DataSeta i LINQ to SQL je ta što u ovom drugom slučaji ne specificiramo SQL upit prilikom formiranja klase odnosno entiteta tabele. U tutorijalu smo vidjeli jedan od načina mapiranja tabele, gdje nam dizajner VS preko modela generiše izvorni kod. Na sljedećoj slici prikazan model baze podataka sa klasom Customers.

lintosql16

Analizirajmo izvorni kod koji je generirao VS. Sljedeća slika pokazuje generirani izvorni kod. Primjetićemo da je VS generirao dvije klase i to:

· NorthWindKlaseDataContext

· Customers

Customers klasa je mapirana tabela Customers baze podataka, dok druga NorthWindDataContext koja klasa obavlja transakcija izmedju klijenta i servera. O DataContext klasi biće riječi kasnije.

lintosql17

Primjetićemo da iznad klase Customers se nalazi Atribut Table koji posjeduje jedan argument i to naziv tabele iz DB. Ovim atributom korespodentna klasa se označava kao klasa generirana prilikom mapiranja tabele iz DB. Ako se naziv klase podudara sa nazivom tabele u DB, kompajler je dovoljno „pametan“ da izvrši mapiranje sa tabelom i bez pomenutog atributa. Isti je slučaj i sa DataContextom.

Implementacija klase Customers je vrlo jednostavna i sastoji se od implementacije osobina (Properties) klase, koje odgovaraju kolonama tabele Customers. Naravno, imamo mogućnost da dodajemo nove osobine (Properties) samo klasi u glavno ako želimo na novou aplikacije da dodajemo dodatne kolone u vidu prekalkulisanih kolona i sl.

Klasa pored spomenutog posjeduje i nekoliko parcijalnih metoda (Partial methods o kojim sam pisao ranije) metode koje se implementiraju po potrebi. Sve osobine klase mogu se pregleavati i u dizajnerskom modulu odnosno podešavati po potrebi.

Osobine klase Customers

Atribute tabele koristimo prilikom formiranja klase (entiteta) u modelu koja korespondira tabeli u DB. Atribute možemo podešavati kako iz dizajnera tako i kroz izvorni kod. Sljedeća slika nam prikazjuje osobine klase Customers, koje većom predstavljaju atribute tebele. Možemo primjeti da postoji samo jedan atribut kojeg možemo promijeniti, a to je naziv (Name) entiteta.

clip_image036

Atribute tabele dobijamo kada desnim klikom iz kontekstnog menija izaberemo opciju Properties.

Osobine članova klase Customers

Svaka generirana klasa posjeduje osobone koje korespondiraju kolonama tabele DB. Na sljedećoj slici su prikazane osobine članova klase, koje u većem broju predstavljaju i same atribute kolona.

clip_image038

Osobine koje predstavljaju i atribute kolona prikazani su masnim fontom.

· Access – identifikator pristupa članu u klasi

· Auto Generated Value (IsDbGenerated)- indikator da se osobina klase (kolona tabele) generira i DB. Ovo uglavnom posjeduju kolone koje su primarni ključevi tabela, a imaju osobinu autogeneriranja vrijednosti. Ako je to slučaj onda pored true vrijednosti ovog atributa, atribut DBType mora imati IDENTITY() oznaku.

· Auto-Sync (AutoSync) – Određuje način sihronizacije kolone (člana klase) nakon što se izvrši upit Insert ili Update. Moguće vrijednosti su: OnInsert – sihroniziraj kada se desi Insert upit, OnUpdate – sihroniziraj kada se desi Update upit, Always – uvijek sihroniziraj vrijednost kolone, Never – nema sihronizacije.

· Delay Loaded – Određuje način učitavanja kolone iz DB prilikom privog pristupa DB. Ovu osobinu korisno je koristiti za BLOB kolone koje sadrže slike ili neke druge velike podatke u koloni. Ova osobina nam omogućava da se vrijednost kolone učitava samo u onom trenutku kada je to zaista potrebno.

· Inheritance Modifer – identifikator preklapanja člana klase.

· Name – naziv člana

· Nullable (CanBeNull) – identifikator stanja vrijednosti. Da li korespodentna kolona može sadržavati NULL vrijednost.

· Pripary Key (IsPrimaryKey) – oznaka kolone da li reprezentira primarni ključ.

· Read Only – identifikator da li član može biti promjenjen.

· Server Data Type – Tip podatka kolone koja je definisana u DB.

· Source (Storage)- Naziv varijable u kojoj se pohranjuju vrijednosti.

· Time Stamp – da li je kolona označena kao TimeStamp.

· Type (DBType)– tip podatka člana.

· UpdateCheck (UpdateCheck) – određuje način na koji LINQ to SQL definiše optimistic concurrency konflikte u DB.Moguće vrijednosti: Always- uvijek koristi kolonu za detekciju konflikta u BD, Never: nekoristi kolonu za detekciju konflikta, WhenChanged : koristi kolonu samo kad je član klase (Entiteta)promjenjen.

Primjer manipulacije tabele Customers pomoću LINQ

Kroz naredni primjer vidjećemo kako koristiti razne LINQ operatore prilikom izvlačenja informacija iz DB. Više informacija o operatorima u LINQ možete naći u pretodnom postu o LINQ. Za ovaj tutorijal slično kao u prethodnom primjeru formirajte Windows Forms C# aplikaciju, te formirajte model DB i mapirajte Tebelu Customers. U Form1 formirajte dataGridView kontrolu i povežite je sa modelom slično kao i u prethodnom slučaju.

Primjer 1. Za privi primjer pokušat ćemo izdvojiti sve partnere čije je sjedište u Londonu. Naš LINQ upit za ovaj slučaj prikazan je na sljedećoj slici.

clip_image040

Poslije pokretanja aplikacije rezulat bi trebao biti kao na sljedečoj slici:

lintosql21

Primjer 2: Potrebno je grupirati sve poslovne partner po gradovima, te u drugoj koloni prikazati broj partnera za svaki grad. LINQ upit za ovaj primjer prikazan je na sljedećoj slici:

clip_image044

Manipulacija nad Master/Detail relacijama

Kako je već kazano LINQ to SQL u potpunosti podržava relacije između tabela u DB. Čak šta više kada je definisana relacija izmedju klasa (entiteta) u dizajneru nije potrebno posebno definisanje relacija (u vidu JOIN naredbe). Ako mapiramo tabele Customers i Orders u dizajner kao na sljedećoj slici možemo primjetiti da se formirala relacija medju njima automatski.

clip_image046

To znači da je dizajner pored mapiranja tabela mapirao i relaciju madju njima jer je ona definisana u DB. Naravno, relaciju medju klasama možemo definisati i ručno. To radimo ako iz ToolBoxa povučemo stavku Asocciationclip_image048.

Ako kliknemo desnom tipkom miša na relaciju i izaberemo opciju Preperties u Property prozoru dostupne su nam osobine relacije.

clip_image050

· Cardinality – vrsta relacije

· Child Property – osobine tabele potomka

· Parent Property – osobine tabele roditelja

· Participating Property – detalji relacije medju tabelama

· Unique – jedinstvenost vanjskog ključa

Primjer manipulacije nad tabelama u Master/Detal relaciji

Koristeći prethodni primjer i dizajner kojeg smo upravo kreirali napravićemo nekoliko primjera svojstvenih ovakvoj zavisnosti medju tabelama.

Primjer 1. Izvucimo sve narudžbe kupaca iz Londona.

Za ovaj primjer LINQ upit izgleda kao na sljedećoj slici.

clip_image052

Ako prokrenemo aplikaciju rezulat dobijamo kao na sljedećoj slici.

lintosql27

Iz ovog primjera vidimo da ako želimo da izvlačimo podatke iz dvije zavisne tabele, dovoljno je da kod deklarisanja klasa definišemo relaciju izmedju njih, a LINQ upite konstruišemo bez naredbe JOIN. Ovo je jeddna od najvažnijih osobina LINQ to SQL. Klasa Order u prethodnom primjeru već ima u sebi sadržave sve kupce (Customers). Najinteresantnije je da se pogleda Log od DataContexta i vidi na koji način se SQL string prosljedio SQL Serveru. Donja slika pokazuje SQL upit koji je prosljeđen SQL Serveru baziran na našem zadnjem primjeru LINQ.

Da bi prikazali u U otput Window SQL koji se prosljedjiva SQL Serveru potrebno je komande iz DataContext – a poslati u Output preko:

clip_image056

Naravno oni koji posjeduju SQL Server mogu pokrenuti profiler i pogledati SQL upite koji dolaze.

clip_image058

Sa slike se vidi da je SQL upit koji je generiran u sebi sadrži SQL komande spajanja (JOIN). Ista situacija se dešava ako povežemo nekoliko tabela hiearhijski u Master/Detail relacije.

Nastavlja se…….

Follow

Get every new post delivered to your Inbox.

Join 549 other followers