
O bazama podataka i kada se koriste
Programi koji od korisnika uzimaju veći broj podataka, koje moraju da čuvaju na čvrstom disku da bi im kasnije pristupali i manipulisali, imaju potrebu za jednostavnim a moćnim sistemom za skladištenje tih podataka. Naravno, uvek možete napraviti ".dat" fajl i "ručno" upisivati podatke u njega, ali to neće biti praktično rešenje kod programa kao što su knjigovodstveni ili kod veb aplikacija koje obrađuju određene podatke. U suštini, gde god je potrebno čuvati logički organizovane podatke, dobro će doći neki RDBMS( Relational DataBase Management System) koji će obaviti "prljavi"deo posla.
Jednostavan primer gde je pogodno koristiti baze podataka je veb aplikacija na kojoj treba napraviti sistem za praćenje posećenosti. U bazi će biti čuvani podaci o posećenosti za svaki dan, a preko SQL jezika tim podacima može se manipulisati, pristupati i to na veoma efikasan način.
Kako rade baze podataka
Imamo tri odvojene celine - kod programa, RDBMS i sam fajl u kojem su smešteni podaci. RDBMS može se posmatrati kao "drajver" - program koji "čuči" između našeg program i samo fajla sa podacima. On će umeti da interpretira SQL komande i vrati nam rezultat ili izvrši neku naredbu. Postoje dve vrste: file-based i serverski RDBMS. Primer za prvi je "MS Access baza podataka", a za drugi MS SQL Server, MySQL i drugi. Jezik kojim pišemo naredbe zove se SQL (Structured Query Language).
Ovo gore je šturo rečeno da bih odmah prešao na konkretnije stvari. Prvo, potrebno je napraviti samu bazu podataka. Pod izradom baze podrazumeva se definisanje tabela, i kolona unutar tih tabela. Jedna baza može imati jednu ili više tabela, a tabela može imati jednu ili više kolona. Kada je baza podataka definisana, u nju je moguće dodavati podatke. Primer jedne definisane tabele, sa nekim već dodatim podacima je i sledeća tabela:
--------------------------------------------------------------------------
| Id | Ime | Prezime | Godiste|
--------------------------------------------------------------------------
| 0 | Nemanja | Todić | 1989 |
--------------------------------------------------------------------------
| 3 | Mitar | Mitrović | 1991 |
--------------------------------------------------------------------------
| 4 | Petar | Petrović | 1882 |
--------------------------------------------------------------------------
... ... ... ... ... ..
Ovde, kolone su Id, Ime, Prezime, Godiste. Zbog toga, svim redovima ove tabele mogu se dodavati samo vrednosti za ta polja( ne može se nekom redu dodati vrednost za polje "Ime oca" jer tabela ne sadrži tu kolonu). Bitno polje svake tabele je "Id" polje (mada se ono može nazvati bilo kako) i ono predstavljam primarni ključ. Primarni ključ je polje po kome će svaki red tabele biti jedinstven. Na primer, mogu postojati dva čoveka sa potpuno istim imenom i prezimenom, pa bi to dovelo do zabune ako bi pretraživanje tabele radili po imenu i prezimenu. Da bi se to izbeglo, dodaje se ta kolona čija će vrednost morati da bude jedinstvena za svaki red ( ako probate da dodate dva reda sa istom Id vrednošću dobićete poruku o grešci).
Obzirom da u bazi obično postoji više tabela, one mogu biti u određenim vezama. Recimo, pred gornje tabele baza može da sadrži i tabelu sa poljima poput Id, MestoStanovanja, Zaposlenje, Telefon i druge. Da bi bili u mogućnosti da odredimo kojem redu iz prve tabele pripada određeni red sa podacima iz druge tabele koristićemo se Id poljem - vrednost Id polja određenog reda prve tabele nalaziće se u Id polju odgovarajućeg redu druge tabele. Da bi se ovakvi uslovi sigurno održali, ali i zbog još nekih stvari, tabele se mogu vezivati relacijama.
Obzirom da bi objašnjavanje procesa pravljenja baze podataka te dodavanja relacija i drugih propratnih stvari oduzelo dosta prostora, preporučiću samo mesto odakle se te stvari mogu naučiti. Na sajtu http://tutoriali.org/ nalazi se kolekcija knjiga na srpskom jeziku iz domena IT-a. U delu sa knjigama o bazama podataka, nalaze se tutorijali i knjige sa potrebnim informacijama. U ovom tutorialu, ja ću koristiti MS Access bazu podataka ( Jet engine 3.5).
Pošto savladate tehnike izrade baza podataka, možemo se pozabaviti SQL jezikom kojim se izvršavaju upiti (Query) i komande (Command) nad bazom podataka a iz vaše aplikacije. U osnovi, SQL je jednostavan jezik, brzo se može savladati i lako se primenjuje. Kao mesto za brzo učenje SQLa preporučujem W3School: http://www.w3schools.com/sql/default.asp a za dalje sajt http://www.sql-tutorial.net/ .
Pravljenje pomoćne klase za pristup bazi iz C#
Za baratanje sa bazama podataka biće nam potrebne klase iz okvira naziva (namespaces) System.Data i System.Data.OleDb, pa ih je pomoću direktive using potrebno uključiti u .cs fajlove. Napomenuo bih da se, generalno gledano, sve klase biti za rad sa bazama mogu podeliti u dve grupe - one koje pružaju mogućnost za komuniciranje sa bazom i one koje služe za pohranjivanje (skladištenje i pristupanje) dobijenim podacima iz baze.
Konektovanje na bazu
Da bismo manipulisali nad bazom podataka, prvo je potrebno konektovati se na nju. Za tu svrhu, .NET biblioteka klasa pruža klasu ˙OleDbConnection. Vrlo je jednostavno koristiti ovu klasu - treba definisati string za konekciju i, otvoriti samu konekciju ka bazi. Zatim se taj objekat klase OleDbConnection može koristiti za pristup i obradu podataka iz baze. U string za konekciju daju se podaci o lokaciji baze, lozinki i još nekim potrebnim parametrima. Problem je u tome što različite baze podataka koriste različite stringove za konekciju. Ovde će biti dat primer za Access bazu, a za ostale konekcione stringove toplo preporučujem sajt http://www.connectionstrings.com.
Sav kod koji bude pisan na dalje sačinjavaće jednu apstraktnu klasu koju sam nazvao BazaPodataka i koja ima par static funkcija. Prvo, napisaćemo funkciju koja koristi OleDbConnection da bi otvorila konekciju prema izvoru podataka.
using System;
using System.Data;
using System.Data.OleDb;
/// <summary>
/// Apstraktna klasa za manipulisanje nad bazom podataka.
/// </summary>
public abstract class BazaPodataka
{
/// <summary>
/// Putanja do fajla koji je izvor podataka.
/// </summary>
public static string LokacijaBaze;
/// <summary>
/// Lozinka kojom je izvor podataka zaštićen.
/// </summary>
public static string Lozinka = string.Empty;
private static OleDbConnection KonektujSe()
{
OleDbConnection oleConn = new OleDbConnection();
string strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + LokacijaBaze +
";Jet OLEDB:Database Password='" + Lozinka + "'";
oleConn.ConnectionString = strCon;
oleConn.Open();
return oleConn;
}
/* .... ostatak koda .... */
}
Unutar f-je KonektujSe(), prvo smo napravili novi objekat oleConn tipa OleDbConnection. Zatim definisan je string za konekciju, koji neću dublje razmatrati, i podesili objekat oleConn da koristi upravo njega. Sledeći korak jeste otvaranje konekcije ka bazi podataka i, na kraju, vraćanje takvog oleConn objekta kao rezultat f-je. Treba obratiti pažnju da posle završetka rada sa OleDbConnection, otvorenu konekciju treba i zatvoriti (što će biti urađeno kasnije u primeru).
OK, sada je tu f-ja koja će "podesiti" konekciju. Ostaje da se napišu rutine za izvršavanje upita i komandi nad izvorom podataka.
Izvršavanje komandi
Da bi se izvršile komande, ali i upiti, koristi se klasa OleDbCommand. Sledi primer pravljenja komande koja će dodati jedan red u tabelu:
string sqlCmd = "insert into korisnici (Ime, Prezime, Godiste) values (@Ime, @Prezime, @Godiste)";
OleDbCommand cmd = new OleDbCommand(sqlCmd, OleDbConnectinObjekat);
cmd.Parameters.AddWithValue("@Ime", "Nemanja");
cmd.Parameters.AddWithValue("@Prezime", "Todić");
cmd.Parameters.AddWithValue("@Godiste", 1989);
int rez = cmd.ExecuteNonQuery();
cmd.Connection.Close();
OleDbCommand ima više konstruktora. Ovde je korišćen onaj koji zahteva SQL komandu koja će se izvršiti i objekat tipa OleDbConnection (primer definisanja ovo objekta je dat ranije). Primetićete da SQL komanda smeštena u string sqlCmd ima deo "values (@Ime, @Prezime, @Godiste)". To su parametri kojima se mogu kasnije dodati vrednosti. Postoji mogućnost da se te vrednosti direktno unesu u string, ali to iz više razloga nije dobro.
Pomenuta dodela vrednosti parametrima radi se kao što je dato ispod:
cmd.Parameters.AddWithValue("@Ime", "Nemanja");
navodeći, dakle, ime parametra (kojem mora prethoditi znak @) i vrednost koja će biti tom parametru dodeljena. Zatim, moguće je izvršiuti napravljenu komadu, što se čini pozivom funkcije ExecuteNonQuery(). Ona vraća broj redova u tabeli koji su bili "zahvaćeni" ovom naredbom.
Na sličan način mogu se izvršavati sve naredbe poput insert, update, delete itd...
Izvršavanje upita
Kao i kod izvršavanja naredbi, i za upite koristi se klasa OleDbCommand. Međutim, ovde je potrebno uvideti ulogu DataTable klase. Kao što je ranije rečeno, kada upitom dobijete povratne podatke iz baze, njih čuvate i pristupate im pomoću DataTable objekta.
Dakle, koristeći se istim metodom kao i kod izvršavanja naredbe dobija se i OleDbCommand objekat sa nekim SQL upitom. Ali to nije sve. Postoji više načina za manupulisanje povratnim informacijama. Ja ću koristiti dodatnu klasu OleDbDataAdapter, koja služi kao adapter koji uzima OleDbCommand objekat a vraća DataTable te ubrzava i olakšava proces dobijanja podataka. Sledi primer.
string sqlSel = "select * from korisnici";
OleDbCommand cmd = new OleDbCommand(sqlSel, OleDbConnectinObjekat);
OleDbDataAdapter adapter = new OleDbDataAdapter(cmd);
DataTable table = new DataTable();
adapter.Fill(table);
cmd.Connection.Close();
Postupak je da se definiše objekat za konekciju, upit i OleDbCommand, zatim DataTable objekat i OleDbDataAdapter, te da se pozove Fill() funckija koja će popuniti DataTable objekat sa podacima koje vrati upit. Kako koristiti DataTable objekat biće objašnjeno uskoro.
Sklapanje kockica
Iz svega što je do sada napisano, može se izvesti sledeća klasa, koju sam inače koristio u par programa jer mi je lakše preko nje da pristupam podacima.
using System;
using System.Data;
using System.Data.OleDb;
/// <summary>
/// Apstraktna klasa za manipulisanje nad bazom podataka.
/// </summary>
public abstract class BazaPodataka
{
/// <summary>
/// Putanja do fajla koji je izvor podataka.
/// </summary>
public static string LokacijaBaze;
/// <summary>
/// Lozinka kojom je izvor podataka zaštićen.
/// </summary>
public static string Lozinka = string.Empty;
private static OleDbConnection KonektujSe()
{
OleDbConnection oleConn = new OleDbConnection();
string strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + LokacijaBaze +
";Jet OLEDB:Database Password='" + Lozinka + "'";
oleConn.ConnectionString = strCon;
oleConn.Open();
return oleConn;
}
public static DataTable IzvrsiUpit(string sqlSelect)
{
OleDbCommand oleCmd = new OleDbCommand(sqlSelect);
return IzvrsiUpit(oleCmd);
}
public static DataTable IzvrsiUpit(OleDbCommand oleSelect)
{
DataTable tabla = new DataTable();
OleDbDataAdapter adapter = new OleDbDataAdapter(oleSelect);
oleSelect.Connection = KonektujSe();
adapter.Fill(tabla);
oleSelect.Connection.Close();
return tabla;
}
public static int IzvrsiNaredbu(string sqlNaredba)
{
OleDbCommand oleCmd = new OleDbCommand(sqlNaredba);
return IzvrsiNaredbu(oleCmd);
}
public static int IzvrsiNaredbu(OleDbCommand sqlNaredba)
{
sqlNaredba.Connection = KonektujSe();
int ret = sqlNaredba.ExecuteNonQuery();
sqlNaredba.Connection.Close();
return ret;
}
}
Osnove korišćenja DataTable objekta
Za ovaj primer biće korišćena konzolna aplikacija i klasa koja je gore predstavljena. Sledeći kod treba da se ubaci u main funkciju:
BazaPodataka.LokacijaBaze = @"c:\baza.mdb";
DataTable table = BazaPodataka.IzvrsiUpit("select * from korisnici");
string ret = string.Empty;
foreach (DataRow row in table.Rows)
{
ret += "Ime:\t" + row["Ime"] + ",\t\tGodiste: \t" + row["Godiste"];
ret += Environment.NewLine;
}
Console.WriteLine(ret);
Klasa DataTable ima niz "Rows" objekata tipa DataRow. DataRow nije ništa do reprezenta reda iz tabele. Svakoj koloni se može pristupati pomoću uglastih zagrada [] između kojih se navodi ime kolone. Na taj način dobija se objekat tipa Object koji, ako je neophodno a u gornjem primeru nije bilo, treba cast-ovati u njegov pravi tip (string, int...).
Kada je reč o WinForms, podaci iz DataTable objekta se mogu automatski prikazivati u vidi mreže (grid) na korisničkom interfejsu korišćenjem kontrole DataGridView (ili bilo koje 3rd-party Grid kontrole). U osnovi, potrebno je samo podesiti DataSource svojstvo tog objekta da bude naša tabela.
Rezime
Eto, cilj je bio da vas uputim u osnove korišćenja baza podataka u .NETu i navedem par zanimljivih lokacija na internetu koje će u tome pomoći. Normalno, sve je bilo jako "usko" i bez dublje "analize" da bi zadržalo jednostavnost. Ako ima pitanja, kritika or samting, navalite. :P
PS. Prikačen je fajl kucan u WordPadu, tamo je lepše foramtirano i obojeno
