Anda di halaman 1dari 8

Conectare la baza de date MS SQL Server folosind C#

ADO.Net
ADO.Net este o multime de biblioteci orientate obiect care permit interactiunea cu sistemele de stocare a informatiilor. De obicei, aceste sisteme sunt reprezentate de bazele de date, dar pot fi si fisiere text, fisiere XML, fisiere Excel, etc. In continuare ne vom ocupa de interactiunea cu bazele de date.

Data Provider
ADO.Net permite interactiunea cu diverse tipuri de baze de date. Totusi, nu exista un singur set de clase care sa pemita acest lucru. Fiecare tip de baza de date foloseste un protocol specific protocoale, deci trebuie sa gasim o metoda pentru a folosi protocolul corect in fiecare caz. Unele sisteme mai vechi folosesc protocolul ODBC, altele mai noi, folosesc protocolul OleDb, etc. ADO.Net furnizeaza metode de comunicare cu fiecare sistem de stocare a informatiilor, fiecare protocol fiind implementat in cate o biblioteca. Aceste biblioteci sunt numite Data Providers si poarta numele protocolului sau sistemului cu care permit interactiunea. Tabelul urmator prezinta o lista a acestor provideri. Provider ODBC Data Provider OleDb Data Provider Oracle Data Provider SQL Data Provider Prefix API Odbc OleDb Oracle Sql Descriere Data Sources care folosesc protocolul ODBC (in mod normal baze date mai vechi). Data Sources care expun interfata OleDb (Access, Excel, etc.) Pentru bazele de date Oracle. Pentru Microsoft Sql Server si MSDE Ofera acces la mai multe tipuri de baze de date cum ar fi Interbase, SQL Server, IBM DB2 si Oracle.

Borland Data Provider Bdp


Fig. 1: Data Providers

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 cu 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"); //sau pentru OleDb OleDbConnection oleDbConn = new OleDbConnection( "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=MyDatabase.mdb"); Obiectul SqlConnection de mai sus este instantiat folosind un constructor care primeste ca parametru un string. Acest argument este stringul de conectare. Parametru al stringului de conectare Data Source Initial Catalog Integrated Security User ID Password

Descriere Identifica masina server. Poate sa fie masina locala, numele unui computer din domeniu sau o adresa IP. Numele bazei de date. Setat la valoarea SSPI pentru a face conexiunea folosind contul windows al utilizatorului. Numele de utilizator configurat pe serverul SQL. Parola atasata utilizatorului de la User ID.

Fig. 2: Stringurile de conectare contin perechi de tipul cheie/valoare despre modul in care se va face conectarea la baza de date.

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. 2. 3. 4. 5. Instantierea unui obiect SqlConnection; Deschiderea conexiunii; Trimiterea conexiunii ca parametru altor obiecte ADO.Net; Realizarea operatiunilor asupra bazei de date; 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 { static void Main() { // 1. Instantiaza conexiunea SqlConnection conn = new SqlConnection( SqlDataReader rdr = null; try { // 2. Deschide conexiunea conn.Open(); // 3. Trimite conexiunea altui obiect ADO.Net SqlCommand cmd = new SqlCommand("SELECT * FROM Customers", conn); // // 4. Realizarea operatiunilor asupra bazei de date // // Obtine rezultatul interogarii rdr = cmd.ExecuteReader(); // Afiseaza valoarea CustomerID a fiecarei inregistrari while (rdr.Read()) { Console.WriteLine (rdr[0]); } } finally { // inchide reader-ul if (rdr != null) { rdr.Close(); } // 5. Inchide conexiunea if (conn != null) { conn.Close(); } } }

"Data

}
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, 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 2 3 4 5 // 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. 1 2 3 4 5 6 7 8 9 // 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 baa de date sa faca ceea ce este necesar si sa intoarca o singura valoare. Acest lucru il face metoda ExecuteScalar: 1 2 3 4 5 // 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 cel mai eficient mod posibil. NU poate fi folosit pentru scriere. Odata citita o informative, aceasta nu mai poate fi citita inca o data. SqlDataReader citeste date secvential. Datprita 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 daca 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.

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. Vom 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 o sursa de date (data source). SqlDataAdapter este cel care se ocupa administrarea conexiunilor cu sursa de date (data source) si ofera posibilitatea de a lucra 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, aceasta 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 in 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. Odata ce avem cele doua instante, DataSet si SqlDataAdapter, putem sa populam DataSetul. daCustomers.Fill (dsCustomers, "Customers"); Metoda Fill din exemplul anterior primeste doi parametri: un DataSet pe care il 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 un DataSet este setat 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. 1 // sa nu faceti asa!! 2 SqlCommand cmd = new SqlCommand( 3 "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 // 1. Declarati un obiect SqlCommand care are stringul de interogare 2 parametrizat 3 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 din figura 16 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 2 3 4 // Definim 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: 1 // Adaugam parametrii definiti obiectului comanda 2 cmd.Parameters.Add(param);

Anda mungkin juga menyukai