Pitanje koje postavljaš zavisi od mnogo faktora.
Jedan od tih faktora je šta koristiš za DTO (Data Transfer Object) u aplikaciji, tj. u komunikaciji među slojevima. Npr, treba ti neki objekat koji puniš u DAL, nad kojim vršiš validaciju i biznis logiku u BL, i koji prikazuješ u UI. Jedan od izbora je DataSet, drugi je custom DTO objekat. Drugi, mnogo važniji faktor, od kojeg i prethodno zavisi, je kako ti je projektovan BL. Ako imaš samo osnovne CRUD operacije, onda ti je prema veličini programa poželjan ili Transaction Script ili Table Module pattern, koji kao DAL koriste neku verziju Gateway pattern-a (opet zavisno od DTO-a). Za veće i kompleksnije programe, te čak i za manje (ako si dobar sa OO konceptima - ali mislim stvarno dobar - OO nije puko deklarisanje klasa), onda Domain Model. Skoro sve što ovdje navodim potiče iz Fowler-ove "Patterns of Enterprise Application Architecture" knjige, tako da ne treba ti tutorial, treba ti ova knjiga, sa prethodno pročitanim GoF Design Pattern-ima.
E sad, DAL ti (striktno i best-practice) gledajući, može biti ili Gateway ili Object-Relational mapping framework. U prvome se najčešće koristi DataSet sa DataAdapterima (i zove se Table Data Gateway), a za drugi si sam naveo primjer - NHibernate.
Ono što tebe vjerovatno brine (i zamara) je količina koda koju trebaš svaki put iznova pisati čak i za najosnovnije sitnice. Evo nešto napisano samo za prikaz koliko je jednostavnije ovo raditi pomoći patterna (ovo dole je Table Data Gateway DAL sa DataSet-ovima):
Treba ti abstraktna nad-klasa, koja preuzima cijelo generičko ponašanje na sebe:
Code:
public abstract class DataGateway : IDisposable
{
protected SqlDataAdapter adapter;
protected SqlConnection conn;
public abstract string TableName { get; }
public DataTable Data { get; set; }
protected DataGateway()
{
Data = new DataTable();
conn = DBProvider.GetConnection();
}
/////////////////////////////////////////////////////////////////////////////
// Generičke metode
/////////////////////////////////////////////////////////////////////////////
public void Load()
{
Data.Clear();
Data.TableName = TableName;
adapter = new SqlDataAdapter("SELECT * FROM " + TableName, conn);
conn.Open();
adapter.Fill(Data);
conn.Close();
}
public void Update()
{
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
adapter.Update(Data);
}
public void Delete(int id)
{
DataRow toDelete = this[id];
toDelete.Delete();
Update();
}
// indexer, za pozivanje gateway[14];
public DataRow this[int id]
{
get { return Data.Select("Id = " + id)[0]; }
}
}
E sad, možda primjećuješ da nedostaje Insert() metoda, ali ona je u biti laka, samo ima nekih varijacija koje radi kompleksnosti nisam sada želio pisati. Samo napomene radi, radi se o problemu kada imaš AutoIncrement (Ident) Primary Key, pa moraš raditi "SELECT Id FROM ... WHERE Id = @@identity ";
Uglavnom, sve što ti sada treba su implementacije Gateway-a, recimo:
Code:
public class OsobaGateway : DataGateway
{
public override string TableName
{
get { return "Osobe"; }
}
}
public class FakturaGateway : DataGateway
{
public override string TableName
{
get { return "Fakture "; }
}
}
itd...
nakon čega se može pozivati:
Code:
OsobaGateway gateway = new OsobaGateway();
gateway.Load();
gateway[12]["Ime"] = "UpdatedName"; // ovo će obilježiti DataRow sa Modified
gateway.Update(); // ovdje će DataAdapter sve Modified, Added i Deleted DataRow-ove sinhronizirati s bazom
Samo za kraj da kažem da je ovo sve samo demonstracije radi, da vidiš jednu od opcija. Obično gdje imaš jedan pattern, imaš ih i 1000 drugih. Npr, NHibernate u sebi sadrži i Identity Map, i Lazy Load, i gomilu drugog. Najbolje ti je da počneš sa čitanjem onih knjiga što sam iznad naveo, pa će ti onda sve biti mnogo jasnije...
My programs don’t have bugs, they just develop random features.