LINQ to SQL audito biblioteka
Parašė Sergejus | 2009-09-01 00:17Pastaruosius du metus aš labai intensyviai dirbu su LINQ to SQL. Per šį laikotarpį teko su juo daryti įvairiausius dalykus - nuo greitaveikos optimizavimo iki automatinio įrašų pakeitimų audito. Pastarąjį šiandien aptarsiu detaliau.
Viename iš projektų man reikėjo sekti visus vartotojų atliekamus veiksmus su duomenimis (pridėjimą, trynimą ir redagavimą) arba kitaip tariant - auditą (angl. Audit Trail). Kadangi visos operacijos su duomenų baze vyksta per duomenų kontekstą, užsinorėjo man specialiai tam skirtos LINQ to SQL audito bibliotekos. Geriausia ką pavyko rasti - Matto biblioteka DoddleAudit. Detaliau ją išanalizavus paaiškėjo, kad tai nevisai ko aš norėjau. Pirma Matto realizacija reikalauja, kad bet kuris duomenų kontekstas paveldėtų iš jo bazinės klasės, kas man buvo nepriimtina. Antra nebuvo galimybės iš karto įjungti visų esybių sekimo. Taigi nusprendžiau parašyti savo paprastą LINQ to SQL audito biblioteką.
Pagrindinis reikalavimas auditui iš mano pusės buvo nustatyti kuris naudotojas kokius veiksmus su duomenimis atliko, kokios laukų reikšmės buvo iki operacijos ir po jos. Tam aš apibrėžiau tokias C# klases:
Pagrindinė klasė yra AuditEntry, ji saugo informaciją apie tai kas atliko pakeitimus, kada, kokioje lentelėje ir kokiam tos lentelės įrašui (EntityTableKey). AuditField saugo senas ir naujas laukų reikšmes, o Action nurodo atliktą veiksmą.
Žemiau pateikiu šių klasių C# kodą:
Pasižiūrėję į klases AuditEntry ir AuditField jums gali kilti klausimas - kodėl aš naudoju POCO C# klases, bet ne LINQ to SQL klases. Aš norėjau šią biblioteką padaryti nepriklausoma nuo konkrečios duomenų bazės struktūros. Šiame pavyzdyje, aš naudosiu tokias AuditEntry ir AuditField atitinkančias duomenų bazės lenteles:
Paskutinė mums reikalinga klasė, o tiksliau atributas - IgnoreAudit:
Kaip ir seka iš pavadinimo, jeigu mums nereikia audituoti tam tikros LINQ to SQL esybės, užtenka partial klasėje tiesiog jai uždėti šį atributą.
Dabar mes jau turime pagrindą, laikas pereiti prie pačios audito logikos. Tam aš esu parašęs statinę klasę AuditExtensions su dviem praplėtimo metodais. Pagrindinis audito metodas yra AuditAndSaveChanges:
Trumpai aptarsiu kas yra daroma:
- Duomenų kontekstas turi labai mums svarbų metodą GetChageSet. Jo pagalba galima gauti visas pridėtas, ištrintas ar redaguotas esybes.
- Metodo viduje kiekvienam iš veiksmų aš kviečiu metodą Audit, kuris tiesiog pasiimą esybę ir pagal ja sukuria AuditEntry objektą.
- Kadangi AuditAndSubmitChagnes bus kviečiamas SubmitChanges metode, mums papildomai reikalingas bazinis SubmitChanges metodas.
- Delegatas transform atsakingas už AuditEntry ir AuditField transformaciją į konkrečias duomenų bazės esybes (mūsų atveju į AuditRecord ir AudifField atitinkamai.
Žemiau pateiksiu pagrindinį šios bibliotekos metodą Audit:
Kaip matote, metodas yra pakankamai ilgas ir sudėtingas. Viskas ką jis daro tai priklausomai nuo atlikto veiksmo (pridėjimo, trynimo, redagavimo) refleksijos pagalba pasiima senas ir naujas laukų reikšmes bei pagal tai sukuria AuditEntry objektus.
Šiame metode aš panaudojau keletą pagalbinių metodų iš SBToolkit projekto, tarp jų:
Štai ir viskas - biblioteka baigta! Bet kaip ja pasinaudoti? Pirma reikia sukurti esamam duomenų kontekstui partial klasę…
… ir perrašyti joje metodą SubmitChanges:
Štai taip, LINQ to SQL audito biblioteka savo rankomis. Čia aprašytą biblioteką galite parsisiųsti iš CodePlex kaip SBToolkit projekto dalį (projektai SBAudit ir SBAudit.LinqToSql).
Tikiuosi šis straipsnis jums bus naudingas ir laukiu komentarų / pasiūlymų dėl šios LINQ to SQL audito bibliotekos!

















Naujausi komentarai