Home - Rasfoiesc.com
Educatie Sanatate Inginerie Business Familie Hobby Legal
Doar rabdarea si perseverenta in invatare aduce rezultate bune.stiinta, numere naturale, teoreme, multimi, calcule, ecuatii, sisteme




Biologie Chimie Didactica Fizica Geografie Informatica
Istorie Literatura Matematica Psihologie

Informatica


Index » educatie » Informatica
» Obiectele ADO.Net


Obiectele ADO.Net


Obiectele ADO.Net

SqlConnection

Primul lucru pe care un programator trebuie sa-l faca atunci cand vrea sa comunice cu o baza de date este sa deschide o conexiune la aceasta. Conexiunea 'spune' celorlalte obiecte cu ce baza de date lucreaza. Conexiunea se ocupa de logica low-level asociata protocolului. Acest lucru usureaza foarte mult munca unui programator, acesta neavand decat sa instantieze obiectul conexiune, sa deschida conexiunea, sa faca operatiile de care are nevoie asupra bazei de date si apoi sa inchida conexiunea. Datorita modului in care celelalte clase ADO.Net sunt implementate uneori este nevoie de chiar mai putin decat atat.

Desi folosirea conexiunilor este mult simplificata in ADO.Net, programatorul trebuie sa le inteleaga foarte bine pentru a lua deciziile corecte. O conexiune este o resursa foarte importanta. Daca aplicatia va fi folosita pe o singura masina, asupra unei singure baze de date, importanta acestei resurse este mai putin clara. Dar daca este vorba de o aplicatie enterprise, folosita simultan de multi utilizatori asupra aceleiasi baze de date importanta conexiunii este mult mai clara. Fiecare conexiune reprezinta overhead pentru server si nu exista nici un server care sa suporte overhead infinit.

Un obiect SqlConnection este la fel ca orice alt obiect C#. de cele mai multe ori declararea si instantierea se face in acelasi timp:



SqlConnection sqlConn = new SqlConnection(
'Data Source=(local);Initial Catalog=Northwind;Integrated Security=SSPI');

Conectarea folosind un cont anume
SqlConnection sqlConn1 = new SqlConnection(
'Data Source=DatabaseServer;Initial Catalog=Northwind;User ID=YourUserID;Password=YourPassword');

Obiectul SqlConnection de mai sus este instantiat folosind un constructor care primeste ca parametru un string. Acest argument este stringul de conectare.

Data Source- Identifica masina server. Poate sa fie masina locala, numele unui computer din domeniu sau o adresa IP.

Initial Catalog- Numele bazei de date.

Integrated Security- Setat la valoarea SSPI pentru a face conexiunea folosind contul windows al utilizatorului.

User ID- Numele de utilizator configurat pe serverul SQL.

Password- Parola atasata utilizatorului de la User ID.

ConnectionTimeout : de tip int, cu accesor de get, valoare implicita 15; specifica numarul de secunde pentru care un obiect de conexiune ar trebui sa astepte pentru realizarea conectarii la server ınainte de a se genera o exceptie. Se poate specifica o valoare diferita de 15 ın ConnectionString folosind parametrul Connect Timeout :

ConnectionString folosind parametrul Connect Timeout :

Se poate specifica pentru Connect Timeout valoarea 0 cu semnificatia "asteapta oricat", dar se sugereaza sa nu se procedeze ın acest mod


Scopul instantierii unui obiect de tip SqlConnection este ca alte obiecte ADO.Net sa poata lucra cu baza de date. Alte obiecte, cum ar fi SqlDataAdapter si SqlCommand, au constructori care primesc obiectul conexiune ca parametru. Atunci cand se lucreaza cu o baza de date trebuie urmati pasii:

  1. Instantierea unui obiect SqlConnection;
  2. Deschiderea conexiunii;
  3. Trimiterea conexiunii ca parametru altor obiecte ADO.Net;
  4. Realizarea operatiunilor asupra bazei de date;
  5. Inchiderea conexiunii.

Exemplul urmator prezinta modul de folosire a unei conexiuni, pas cu pas:

using System;
using System.Data;
using System.Data.SqlClient;

// Prezinta modul de lucru cu un obiect SqlConnect
class SqlConnectionDemo

}
finally


Inchid conexiunea la baza de date. Ramura finally se executa indiferent daca a fost o eroare sau nu (s-a intrat pe catch sau nu)


if (conn != null)

}
}

}

Asa cum se vede la linia 19 deschiderea conexiunii se face apeland metoda Open() a instantei SqlConnection. Orice operatii asupra unei conexiuni care nu a fost inca deschisa genereaza o exceptie.

Inainte de a folosi conexiunea trebuie sa instiintam celelalte obiecte ADO.Net despre care conexiune este vorba. Facem acest lucru la linia 22 din figura 4, trimitand ca parametru constructorului SqlCommand obiectul conn. Orice operatie pe care o va face instanta cmd va folosi aceasta conexiune.

Obiectul care foloseste conexiunea este cmd, de tipul SqlCommand. Acesta face o interogare in baza de date adupra tabelului Customers. Rezultatul este intors intr-un obiect de tipul SqlDataReader, iar in bucla while este afisat continutul primei coloane din fiecare rand din tabelul obtiunut (noi stim ca aceasta coloana este coloana CustomerID). Important de retinut este ca obiectele SqlCommand si SqlDataReader folosesc un obiect de tipul SqlConnection, si astfel stiu cu care baza de date sa lucreze.

Atunci cand am terminat de folosit obiectul conn inchidem conexiune (linia 48). Lasarea conexiunii deschise are implicatii grave in performanta aplicatiei.

SqlCommand

Obiectele de tipul SqlCommand permit specificare tipului de actiune asupra bazei de date. De exemplu se poate face o interogare, inserare, modificare sau stergere

Instantierea unui obiect de tipul SqlCommand se face ca la linia 22 din figura 4. Aceste este modul cel mai des intalnit de instantiere. Ia ca parametru un string, care este comanda ce va fi executata, si o referinta la un obiect de tipul SqlConnect.

Atunci cand faci o interogare in baza de date, obtii un tabel rezultat care trebuie sa poata fi vizualizat. Pentru a obtine acest lucru folosind obiecte SqlCommand este folosita metoda ExecuteReader care intoarce un obiect de tipul SqlDataReader. Exemplul de mai jos arata modul de obtinere a unei instante SqlDataReader.

// 1. Instantiaza o noua comanda cu o fraza select si o conexiune
SqlCommand cmd = new SqlCommand ('SELECT CategoryName FROM Categories', conn);

// 2. Executa interogarea

SqlDataReader rdr = cmd.ExecuteReader();

Pentru a insera valori intr-o baza de date trebuie apelata functia ExecuteNonQuery pe un obiect SqlCommand. Exemplul urmator arata modul de inserare intr-o baza de date.

// pregateste stringul comanda
string insertString = @'INSERT INTO Categories (CategoryName, Description)
VALUES ('Miscellaneous', 'Whatever doesn''t fit elsewhere')'

// 1. Instantiaza o noua comanda
SqlCommand cmd = new SqlCommand (insertString, conn);

// 2. Apeleaza ExecuteNonQuery pentru a executa comanda

cmd.ExecuteNonQuery();

Modificarea si stergerea datelor dintr-o baza de date se face la fel ca si inserarea, dar ca punem primul parametru al constructorului SqlCommand pe valoarea corespunzatoare.

Uneori avem nevoie dintr-o baza de date doar de o singura valoare, care poate fi suma, media, etc. inregistrarilor dintr-un tabel. Apeland ExecuteReader si apoi calculand acea valoare in program nu este cea mai eficienta metoda de a ajunge la rezultat. Cea mai buna metoda este sa lasam baza de date sa faca ceea ce este necesar si sa intoarca o singura valoare. Acest lucru il face metoda ExecuteScalar:

// 1. Instantiaza o noua comanda
SqlCommand cmd = new SqlCommand ('SELECT count(*) FROM Categories', conn);

// 2. Apeleaza ExecuteScalar pentru a executa comanda

int count = (int) cmd.ExecuteScalar();

SqlDataReader

Tipul SqlDataReader este folosit pentru a citi date in cea mai eficienta metoda posibila. NU poate fi folosit pentru scriere. O data citita o informatie nu mai poate fi citita inca o data. SqlDataReader citeste secvential date.

Datorita faptului ca citeste doar inainte (forward-only) permite acestui tip de date sa fie foarte rapid in citire. Overhead-ul asociat este foarte mic (overhead generat cu inspectarea rezultatului si a scrierii in baza de date). Daca intr-o aplicatie este nevoie doar de informatii care vor fi citite o singura data, sau rezultatul unei interogari este prea mare ca sa fie retinut in memorie (caching) SqlDataReader este solutia cea mai buna.

Obtinerea unei instante de tipul SqlDataReader este putin diferita de instantierea normala - trebuie apelata metoda ExecuteDataReader. Daca pentru instantiere este folosit operatorul new veti obtine un obiect cu care nu puteti face nimic pentru ca nu are o conexiune si o comanda atasate.

SqlDataReader obtine datele intr-un stream secvential. Pentru a citi aceste informatii trebuie apelata metoda Read; aceasta citeste un singur rand din tabelul rezultat. Metoda clasica de a citi informatia dintr-un SqlDataReader este de a itera intr-o bucla while.

Metoda Read intoarce true cat timp mai este ceva de citit din stream.

SqlDataReader implementeaza si indexatori :

// Obtine rezultatul interogarii
rdr = cmd.ExecuteReader();

// Afiseaza valoarea CustomerID a fiecarei inregistrari
while (rdr.Read())

Valoare indexului trebuie sa fie numele coloanei din tabelul rezultat.

Indiferent ca se foloseste un index numeric sau unul de tipul string indexatorii intorc totdeauna un obiect de tipul object fiind necesara conversia.

Dupa ce un reader nu mai este folosit acesta trebuie inchis apeland metoda

Metoda ExecuteReader() mai poate lua un argument optional de tip

enumerare CommandBehavior care descrie rezultatele si efectul asupra bazei de date:

. CommandBehavior.CloseConnection - conexiunea esteınchisa atunci cand obiectul de tip IDataReader este ınchis.

. CommandBehavior.KeyInfo - comanda returneza informatie despre coloane si cheia primara.

. CommandBehavior.SchemaOnly - comanda returneza doar informatie despre coloane.

. CommandBehavior.SequentialAccess - da posibilitatea unui DataReader

sa manipuleze ınregistrari care contin campuri cu valori binare de mare ıntindere. Acest mod permite ıncarcarea sub forma unui flux de date folosind GetChars() sau GetBytes().

. CommandBehavior.SingleResult - se returneaza un singur set de rezultate

. CommandBehavior.SingleRow - se returneaza o singura linie. De exemplu, daca ın codul anterior ınainte de while obtinerea obiectului reader s-ar face cu:

SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow);

Proprietati

1. IsClosed - proprietate read-only, returneaza true daca obiectul este deschis, false altfel

2. HasRows - proprietate booleana read-only care spune daca readerul contine cel putin o ınregistrare

3. Item - indexator care da acces la campurile unei ınregistrari

4. FieldCount - da numarul de campuri din ınregistrarea curenta

Metode

1. Close() - ınchide obiectul de citire si elibereaza resursele client. Este obligatoriu apelul acestei metode inaintea ınchiderii conexiunii.

2. GetBoolean(), GetByte(), GetChar(), GetDateTime(), GetDecimal(),

GetDouble(), GetFloat(), GetInt16(), GetInt32(), GetInt64(), GetValue(),

GetString() returneaza valorile campurilor din ınergistrarea curenta.

Preiau ca parametru indicele coloanei a carei valoare se cere. GetValue() returneaza un obiect de tip Object, pentru celelalte tipul returnat este descris de numele metodelor.

3. GetBytes(), GetChars() - returneaza numarul de octeti / caractere cititi dintr-un camp ce stocheaza o structura de dimensiuni mari; primeste ca parametri indicele de coloana (int), pozitia din acea coloana de unde se va ıncepe citirea, vectorul ın care se face citirea, pozitia ın buffer de la care se depun datele citite, numarul de octeti/caractere ce urmeaza

a fi cititi.

4. GetDataTypeName() - returneaza tipul coloanei specificat prin indice

5. GetName() - returneaza numele coloanei

6. IsDBNull() - returneaza true daca ın campul specificat prin index este

o valoare de NULL (din baza de date)

7. NextResult() - determina trecerea la urmatorul rezultat, daca aceasta

exista; ın acest caz returneaza true, altfel false (este posibil ca ıntr-un DataReader sa vina mai multe rezultate, provenind din interogari diferite)

8. Read() - determina trecerea la urmatoareaınregistrare, daca aceasta exista ın acest caz ea returneaza true. Metoda trebuie chemata cel putin o data, deoarece initial pozitia curenta este ınaintea primei ınregistrari.

Urmatoarele observatii trebuie luate ın considerare atunci cand se lucreaza cu un obiect DataReader :

. Metoda Read() trebuie sa fieıntotdeauna apelataınaintea oricarui acces la date; pozitia curenta la deschidere este ınaintea primei ınregistrari.

. Intotdeauna apelati metoda Close() pe un DataReader si pe conexiunea asociata cat mai repede posibil; ın caz contrar conexiunea nu poate fi reutilizata

. Procesarea datelor citite trebuie sa se faca dupa ınchiderea conexiunii; ın felul acesta conexiunea se lasa libera pentru a putea fi reutilizata.

Este posibil ca ıntr-un DataReader sa se aduca mai multe seturi de date.

Acest lucru ar micsora numarul de apeluri pentru deschiderea unei conexiuni la stratul de date. Obiectul care permite acest lucru este chiar cel de tip Command:

string select = 'select * from Categories; select * from customers';

SqlCommand command = new SqlCommand ( select, conn );

conn.Open ();

SqlDataReader reader = command.ExecuteReader ();

Trecerea de la un set de date la altul se face cu metoda NextResult() a

obiectului de tip Reader :

do

tt', reader[0], reader[1] );

}

}while ( reader.NextResult () );

SqlDataAdapter

Pana acum am vazut cum putem efectua operatii asupra unei baze de date folosind obiecte de tipul SqlCommand si SqlDataReader. Problema cu aceasta abordare este ca pe parcursul intregii tranzactii conexiunea trebuie sa fie deschisa.

Voi prezenta in continuare o metoda care nu necesita o conexiune permanenta la o baza de date - si anume folosind obiecte de tipul DataSet si SqlDataAdapter.

Un DataSet este o reprezentare in memorie a unui data store (un sistem de stocare si obtinere a datelor). Un DataSet contine o multime de tabele asupra carora se pot executa diverse operatii. Un DataSet doar retine informatii si nu interactioneaza cu un data source. SqlDataAdapter este cel care se ocupa administrarea conexiunilor cu data source si ofera comportamentul de lucru in mod deconectat. SqlDataAdapter deschide o conexiune doar atunci cand este nevoie si o inchide imediat ce si-a terminmat treaba. De exemplu SqlDataAdapter realizeaza urmatoarele operatiuni atunci cand trebuie sa populeze un DataSet:

  1. deschide conexiunea;
  2. populeaza DataSet-ul;
  3. inchide conexiunea;

si urmatoarele operatiuni atunci cand trebuie sa faca update in baza de date:

  1. deschide conexiunea;
  2. scrie modificarile din DataSet in baza de date;
  3. inchide conexiunea;

Intre operatiunea de populare a DataSet-ului si cea de update conexiunile la data source sunt inchise. Intre aceste operatii in DataSet se poate scrie sau citi. Acestea sunt mecanismele de a lucra in mod deconectat. Pentru ca aplicatia tine deschisa conexiunea la baza de date doar atunci cand este necesar, devine mai scalabila.

Crearea unui obiect de tipul DataSet se face folosind operatorul new

DataSet dsCustomers = new DataSet ();

Constructorul unui DataSet nu necesita parametri. Exista totusi o supraincarcare a acestuia care primeste ca parametru un string, si este folosit atunci cand trebuie sa se faca o serializare a datelor intr-un fisier XML. In acest moment avem un DataSet gol si avem nevoie de un SqlDataAdapter pentru a-l popula.

Un obiect SqlDataAdapter contine mai multe obiecte SqlCommand si un obiect SqlConnection pentru a citi si scrie date.

SqlDataAdapter daCustomers = new SqlDataAdapter ('SELECT CustomerID, CompanyName FROM Customers', conn)

Codul de mai sus creaza un obiect de tipul SqlDataAdapter, daCustomers. Comanda SQL specifica cu ce date va fi populat un DataSet, iar conexiunea conn trebuie sa fi fost creata anterior, dar nu si deschisa. Responsabilitatea deschiderii conexiunii revine adapterului la apelul metodelor Fill si Update.

SqlDataAdapter contine mai multe obiecte comanda: cate unul pentru inserare, update, delete si select. Prin intermediul constructorului putem instantia doar comanda de interogare. Instantierea celorlalte se face fie prin intermediul proprietatilor pe care le expune SqlDataAdapter, fie folosind obiecte de tipul SqlCommandBuilder.

SqlCommandBuilder cmdBldr = new SqlCommandBuilder (daCustomers);

La initializarea unu SqlCommandBuilder am apelat un constructor care primeste ca parametru un adapter, pentru care vor fi construite comenzile. SqlCommandBuilder are limitari: nu poate construi decat comenzi simple si care se aplica unui singur tabel. Atunci cand trebui ca sa facem comenzi care vor folosi mai multe tabele este recomandata construirea separata a comnezilor si apoi atasarea lor adapterului folosind proprietati.

O data ce avem cele doua instante, DataSet si SqlDataAdapter, putem sa populam DataSet-ul.

daCustomers.Fill (dsCustomers, 'Customers');

Metoda Fill din exemplul anterior primeste doi parametri: un DataSet pe care-l va popula si un string care va fi numele tabelului (nu numele tabelului din baza de date, ci al tabelului rezultat in DataSet) care va fi creat. Scopul acestui nume este identificarea ulterioara a tabelului. In cazul in care nu este specificat nici un nume de tabel, acestea vor fi adaugate in DataSet sub numele Table1, Table2,

Un DataSet poate fi folosit ca data source pentru un DataGrid atat in ASP.Net cat si pentru cel din Windows Forms. Mai jos este prezentat un exemplu de legare a unui DataSet la un DataGrid:

DataGrid dgCustomers = new DataGrid();
dgCustomers.DataSource = dsCustomers;

dgCustomers.DataMembers = 'Customers';

La linia 2 setez un DataSet ca DataSource pentru un DataGrid. Acest lucru ii spune grid-ului ce informatii sa afiseze. Un grid stie sa afiseze mai multe tabele dintr-un DataSet, afisand un semn '+' permitandu-i utilizatorului sa aleaga care tabel sa fie afisat din cele disponibile. Pentru a suprima afisarea acelui semn '+' din GUI am setat si proprietatea DataMembers pe numele tabelului care va fi afisat. Numele tabelului este acelasi care l-am folosit ca parametru in apelul metodei Fill

Dupa ce au fost facute modificari intr-un DataSet acestea trebuie scrise si in baza de date. Actualizarea se face prin apelul metodei Update

daCustomers.Update (dsCustomers, 'Customers');

SqlParameter

Atuci cand lucrati cu bazele de date veti avea nevoie, de cele mai multe ori sa filtrati rezultatul dupa diverse criterii. De obicei acest lucru se face in functii de niste criterii pe care utilizatorul le specifica (ex: vreti sa vedeti doar clientii anume oras).

Dupa cum am vazut, o interogare asociata unui obiect SqlCommand este un simplu string. Cea mai simpla metoda de filtrare a rezultatelor este sa construiti acel string in mod dinamic, dar aceasta metoda nu este recomandata.

// sa nu faceti asa!!
SqlCommand cmd = new SqlCommand(

'SELECT * FROM Customers WHERE city = '' + inputCity + ;

Motivul pentru care o astfel de construire a unei interogari este nerecomandata este ca nu se poate avea incredere in input-ul utilizatorului. De obicei inputCity este introdus de utilizator intr-un TextBox. Folosind acel TextBox un utilizator rau intentionat poate sa introduca cod care poate duce la coruperea bazei de date, accesarea informatiilor confidentiale, etc.

In loc sa construiti dinamic stringul de interogare folositi interogari cu parametri. Orice valoare pusa intr-un parametru nu va fi tratata drept cod SQL, ci ca valoare a unui camp, facand aplicatia mai sigura. Pentru a folosi interogari cu parametri urmati pasii:

  1. Construiti stringul pentru SqlCommand folosind parametri;
  2. Creati un obiect SqlParameter asignand valorile corespunzatoare;
  3. Adaugati obiectul SqlParameter la obiectul SqlCommand, folosind proprietatea Parameters.

Deci primul pas este construirea unui string de interogare parametrizat. Pentru a specifica locul unde vor fi inserate valorile parametrilor folositi marcatorul @. Sintaxa este urmatoarea:

// 1. Declarati un obiect SqlCommand care are stringul de interogare parametrizat
SqlCommand cmd = new SqlCommand(

'SELECT * FROM Customers WHERE city = @City', conn);

In contructorul din exemplul anterior stringul de interogare contine un parametru @City. Atunci cand comanda va fi executata in string @City va fi inlocuit cu valoarea aflata in obiectul SqlParameter atasat. In exemplul de mai sus folosim o interogare cu un singur parametru, dar pot exista oricati parametri, si pentru fiecare din acestia trebuie sa asociem un obiect SqlParameter. In cazul in care pentru un parametru din stringul de interogare nu avem asociata o instanta de tipul SqlParameter vom obtine o eroare la rulare. Acelasi lucru se intampla si daca avem mai multe instante SqlParameter pentru un parametru.

Acum trebuie sa declaram o instanta de tipul SqlParameter:

// 1. Definiti parametrii utilizati in stringul de interogare
SqlParameter param = new SqlParameter();
param.ParameterName = '@City';

param.Value = inputCity;

Si acum trebuie sa adaugam acet parametru obiectului comanda:

cmd.Parameters.Add(param);

Tranzactii

O tranzactie este un set de operatii care se efectueaza fie ın ıntregime,fie deloc.

Tranzactiile satisfac niste proprietati

. atomicitate - toate operatiile din tranzactie ar trebui sa aiba success sau sa esueze ımpreuna

. consistenta - tranzactia duce baza de date dintr-o stare stabila ın alta

. izolare - nici o tranzactie nu ar trebui sa afecteze o alta care ruleaza ın acelasi timp

. durabilitate - schimbarile care apar ın tipul tranzactiei sunt permanent stocate pe un mediu.

Sunt trei comenzi care se folosesc ın context de tranzactii:

. BEGIN - ınainte de executarea unei comenzi SQL sub o tranzactie, aceasta trebuie sa fie initializata

. COMMIT - se spune ca o tranzactie este terminata cand toate schimbarile cerute sunt trecute ın baza de date

. ROLLBACK - daca o parte a tranzactiei esueaza, atunci toate operatiile efectuate de la ınceputul tranzactiei vor fi neglijate

Schema de lucru cu tranzactiile

1. deschide conexiunea la baza de date

2. ıncepe tranzactia

3. executa comenzi pentru tranzactie

4. daca tranzactia se poate efectua (nu sunt exceptii sau anumite conditii sunt ındeplinite), efectueaza COMMIT, altfel efectueaza ROLLBACK

5. ınchide conexiunea la baza de date





Politica de confidentialitate





Copyright © 2024 - Toate drepturile rezervate