0 Comments

sqlmigrationJedna od čestih tehnika rada sa bazom, obavezna u ozbiljnijim firmama sa programerskim timovima, ali i popularizirana u Ruby on Railsu, je izrada migracijskih skripti. Radi se o kontinuiranoj izradi skripti koje upravljaju sa shemom baze. Drugim riječima, ne smije direktno mijenjati baza, jer se time izgube informacije tko je, kada i što promijenio, nego se rade kratke skripte, i svaka se nazove ili notira datumom (timestamp-om). Da bi se baza kreirala, dovoljno je pokrenuti sve skripte.

Jedan način izrade migracijskih skripti je pisanje SQL-a unutar običnih textualnih (.sql) fajlova, koje je moguće izvršiti u SQL Management Studio, ili nekom drugom alatu. Da bi automatizirali to, pratili u kojoj je “verziji” naša baza (koja je zadnja skripta izvršena), trebati će nam neki alat. U .NET svijetu ih ima nekoliko. Svi oni rade na slični princip, stoga opisana procedura ovdje vrijedi i za ostale alate. Pokazati ću rad sa FluentMigratorom, kojega ja upotrebljavam u svojim web projektima.

Ovaj alat je C# apstrakcija nad generiranjem SQL skripti i baze podataka, što znači da se koristi fluent API za kreiranje skripti, i željeni database provider ovisno o bazi (MS SQL, MySQL, SQLite, Jet, Oracle, Postgres). Sastoji se od DLL biblioteke koja sadrži fluent API klase, i runnera, .EXE izvršne datoteke koja pokreće skripte. Runner se može pokrenuti po želji, i on će izvršiti samo skripte koje nedostaju, odnosno od zadnjeg pokretanja, jer u bazi postoji podatak o trenutnoj verziji. Također, runner je pogodan za pokretanje u sklopu build procesa.[more]

Strukturiranje projekta

Da bi runner izvršio migracijske skripte, mora mu se dati DLL koji sadrži migracije. Možda najjednostavnije je kreirati jedan class library, i u njemu držati sve migracije. Projektu je potrebni postaviti referencu na FluentMigrator.

Kreiranje migracijskih skripti

Migracija skripta je obična klasa, koja nasljeđuje Migration klasu i ima atribut sa parametrom rednog broja skripte. Primjer:

Metoda Up se pokreće kod izvršavanja i postavljanja baze na posljednju verziju, a Down se ako želimo vratiti na određeno stanje u prošlosti i poništiti promijene.

Fluent API sadrži sve potrebne metode za CREATE, DELETE, ALTER tablica, ali i dodavanje podataka u bazi i izvršavanje vanjskih skripti (dodavanje Stored procedura, …). Moguće je kreirati i indexe:

Izvršavanje skripti

Skripte se izvršavaju nad bazom pokretanjem migrate.exe datoteke, uz potrebne parametre. Spisak svih parametra je dostupan na službenim stranicama. Primjer komande:

migrate.exe /conn "Data Source=App.Web\App_Data\db.sqlite;Version=3" /db sqlite /target "App.Migrations\bin\debug\App.Migrations.dll"

U svojim projektima sam tek nedavno počeo koristiti migracijske skripte, te iako nemam neku potrebu vračanja stanja baze u stariju verziju i slično, ne moram tražiti management alat za upravljanje bazom (za SQLite u ovom slučaju), promjene su jasno vidljive iz koda, lakše je kreiranje raznih ključeva i indexa, jer svaki management alat ima specifičnosti, i rad sa bazom je ugodniji i lakši. U kompleksnijim okruženjima, testing i deployment fazama, izvršavanje migracijskih skripti je sigurno lakše od backup/restore procedure.

2 Comments

Potaknut Ayendeovim blog postovima vezanim za arhitekturu, DDD, i projektiranje strukture aplikacije, nekako osjećam potrebu napisati par riječi.

Poruka koja se proteže kroz gotovo sve Ayendeove postove je uvijek ista, a govori o jednostavnim rješenjima za jednostavne probleme, i kompleksnim za kompleksne probleme. Bilo kakva drugačija kombinacija nije dobra, naravno, i logično!

Northwind starter kit je samo jedan u nizu primjera kako rješenje za 2+2 napisati u obliku SIN(4)^2 + COS(4) ^2 + SQRT(9). Svako toliko kada tražim primjer za neki problem, pattern, funkciju, skinem projekt sa codeplexa ili nekog drugog repozitorija, otvorim ga u Visual Studio, i čudim se kako su uspjeli napisati toliko linija koda za izvući jedan redak iz baze, ubaciti toliko layera apstrakcije i interfaceova. Takvi primjeri, koji su pretpostavljam namijenjeni za učenje, davanje savjeta i dobrih praksi, vjerujem da samo u manjem dijelu i zadovoljavaju tu svoju svrhu, ali u većem dijelu čine kontra-efekt, i udaljavaju "čitatelja" od dobivanja korisnih znanja.

Iz vlastitog iskustva mogu opisati kako sam godinama samo tražio priliku za ubaciti dodatne klase u projekt koje bu služile kao repozitorij, service layer, application layer, pa još neki kvazi-BLL layer, zamjenjivi ORM framework, pa sve to odvojiti u posebne projekte, i neka komuniciraju preko web servisa i SOAP protokola, jer tko zna kakva će biti produkcijska infrastruktura. A radi se o aplikaciji za spremanje brojeva telefona, ili evidencije radnog vremena. U stručnoj literaturi znano kao najobičnija CRUD aplikacija. Ali trebalo je isprobati sve patterne od Martin Fawlera (PoEAA) i Eric Evansa (DDD)!

Kvaliteta koda se prvo očituje u njegovoj jednostavnosti da riješi zadani problem. Odmah poslije toga bi postavio pridržavanje SOLID principa, jer su oni direktno vezani za dobar objektni dizajn - što u prijevodu govori u lakšem održavanju, izmijeni i testiranju. A sve to iziskuje puno rada, truda, učenja, ali i mijenjanja i preispitivanja vlastitih sudova. Mislim da ću si odmah napisati na stick-it notes "jednostavno i solid-no", i zalijepiti ga na monitor, da ne zalutam previše:)