Repository design med LINQ – object-relational mappers

by DotNetNerd 10. May 2009 14:25

Object-Relational Mappers eller bare ORM’s er værktøjer der håndterer det at mappe imellem relationelle data i en database til objekter som vi gerne vil arbejde med dem (og tilbage igen naturligvis). Der findes efter hånden et hav af forskellige ORM eller ORM-lignendene værøtøjer hvor nogen af de mest udbredte er SubSonic, LightSpeed, NHibernate, LINQ to SQL og LINQ to Entities.

Personligt er det de 3 sidstnævnte jeg hovedsageligt har erfaring med, og hvor NHibernate er det jeg primært anvender idag. Der er mange ting at vurdere når man vælger et ORM, men det der normalt afgør ens valg er kompatibilitet med andre teknologier, hvor “tungt” frameworket er og hvor fleksibelt det er. Med fleksibilitet menes her normalt hvordan man kan beskrive sine mapninger og hvilke typer mapninger der er mulige. Det er eksempelvis ikke alle der understøtter mange-til-mange relationer.

Som helt kort guideline vil jeg idag anbefale NHibernate hvis man skal have mest mulig fleksibilitet, LINQ to Entities hvis man vil have best mulig kompatibilitet med .NET teknoligier (især kommende teknologier) og en af de sidst hvis man gerne vil have et mere letvægts ORM der er let at gå til.

Jeg skal muligvis passe på med at kalde LINQ to SQL/Entities for ORM’s, da især Microsoft argumenterer for at de er noget lidt andet. De fleste anser dem dog som ORM’s, og jeg vil også argumentere for at det er hvad produktet er “at it’s core”.

En anden udbredt misforståelse er at LINQ i sig selv er en database teknologi og har noget med et ORM at gøre. Det er imidlertid forkert, da LINQ udelukkende som navnet (Language INtegrated Query) antyder er et sprog til at skrive querys imod en eller anden for for datastore. LINQ providerne til SQL/Entities udgør imidlertid hvad jeg vil kalde ORM’s, da de netop håndterer mapning og persistering af data i databaser.

Der findes en version af LINQ to NHibernate, som efter min mening giver den bedste blanding af et gennemprøvet og fleksibelt modelleringsværktøj i NHibernate, sammen med et lækkert query sprog i LINQ. Til komplekse querys har det imidlertid stadig nogle fejl og mangler, så træerne vokser ikke ligefrem ind i himlen.

En af de ting der bliver talt en del om idag, og som især LINQ to SQL/Entities bliver kritiseret for ikke at give er en Persistence Ignorent domænemodel.

“Persistence ignorance (PI) is a property of "ordinary classes where you focus on the business problem at hand without adding stuff for infrastructure-related reasons.”

Det vil sige om man skal skrive kode i selve modellen der beskriver hvordan objekterne mappes, og om valget af ORM stiller nogen krav til ens øvrige kode.

PI er især et fokusområde for agile udviklere, og det er heldigvis et område Microsoft har fået øjnene op for, således at de har arbejdet på at opnå PI med LINQ to Entities i v2. Lige som afsluttende bemærkning kan jeg nævne at successen med at implementere det nok kommer til at afgøre mit valg af ORM fremover.

disco%20orm1

Tags: ,

Repository design med LINQ - DDD principper

by DotNetNerd 3. May 2009 19:50

I Eric Evans bibel om Domain Driven Design skriver han "any object internal to an aggregate is prohibited from access except by traversal from the root". Det vil altså sige at man skal have et repository pr aggregate root, og at interne objekter kun må tilgås via navigation for at sikre indkapsling. Derudover må externe objekter kun må holde referencer til rooten og transient references til value objekter.

Kunsten ved at designe sine repositories på den måde er at få defineret sine aggregate roots rigtigt. Laver man et design hvor man anser en klasse som værende en del af en aggregate, og man senere erfarer at der skal kunne søges på properties på objektet og vises lister af dem, vil det kræve en refaktorering, da denne nu må være root.

Nogen typer systemer er karaktaristiske ved at næsten alle klasser kan ses som lister og er søgbare - i den typer systemer vil repository designet begynde at ligne en en-til-en mapning med de tabeller man har i databasen. Man kan imidlertid argumentere for at så længe det forhold opstår af den årsag er det ikke symptom på at designet er databasedrevet, men blot den naturlige måde at designe systemet på. Service orienterede løsninger vil som eksempel i mange tilfælde fungere naturligt på den måde.

Personligt kan jeg godt lide DDD måden at tænke repositories på, da det sikrer indkapsling og lægger op til at persistence ignorence ved at man undgår at repositories blot afspejler databasestrukturen. Dog vil jeg understrege ordet principper - da disse ofte er til for at blive brudt.

Jeg er jævnligt løbet på systemer hvor granuleringen af klasser og metoder bliver unaturligt hvis man følger fremgangen slavisk. Her kan det eksempelvis være en mulighed at lade repositories have metoder til at søge efter objekter der er interne i en aggregate - selvom det bryder direkte med ovennævnte principper.

Andre gange kan det virke helt naturligt at anskue dataaccess som mapning af tabeller - både fordi den teknologi man anvender til dataaccess låner sig bedre til det, og i systemer der af natur er meget datadrevne. RAD og udvikling af prototyper kan også i sig selv som princip være en modsætning, da det at designe repositories omkring aggregates kræver mere designmæssigt omhu.

 

Tags:

Repository design med LINQ

by DotNetNerd 3. May 2009 13:19

Repositories er omdrejningspunktet i de fleste webapplikationer, og et godt repository design er derfor vigtigt. Jeg tror de fleste har prøvet at fortryde et designvalg i forhold til repositories og tænkt “why didn’t I take the blue pill”.

Da jeg startede som udvikler lærte jeg, ligesom så mange andre, at bygge et dataaccess lag hvor man typisk havde en klasse der håndterede adgang til en enkelt tabel i databasen. Det betød at database designet leakede ud i hele applikationen som blev databasedrevet. Sidenhen er ORM’s og DDD blevet mere udbredt og PI (Persistence Ignorance) tilstrebes. Samtidig er LINQ blevet den foretrukne måde at udtrykke querys på, hvilket giver en række nye design muligheder/beslutninger.

Derudover er der forskellige “skoler” med hensyn til om man mener querys bør indkapsles i et repository, eller om de skal ses som en del af ens business logic, og måske ligefrem være fuldgyldige objekter. Transaktioner og validering har desuden stor indflydelse på hvordan det kan være hensigtsmæssigt at designe sit repository - og hvordan det samlede design har indvirkning på hvordan applikationen struktureres.

For nylig læste jeg så en række blogposts der kan findes via CodeBetter’s “Reposptiry is dead: Long live repository”, hvor der netop blev diskuteret repository design, hvilket fik mig til også at tænke en ekstra gang over designet i mit nuværende projekt. Med udgangspunkt i de ting vil jeg derfor skrive en lille serie posts om emnet, hvor jeg i vilkårlig rækkefølge vil se på emner som:

  • DDD principper
  • Object-Relational Mappers
  • Repositories som singletons
  • Querying: fleksibilitet og indkapsling
6644The_red_pill_or_the_blue_pill

Tags: , ,

Pendlerscrumagileliv

by DotNetNerd 7. April 2009 16:59

Hvis Jokerens liv er et Junkiegøglercirkusliv må jeg betegne mit nye liv som et pendlerscrumagileliv. (Be warned: det her er en af de lidt bløde artikler om mig selv, og mine erfaringer - sorry).

Fra årsskiftet begyndte jeg at arbejde hos Vertica i Århus, men er stadig bosiddende i Odense. Det at skulle pendle var jeg spændt på da jeg tog imod jobbet, men det har vist sig ikke at være så hårdt som jeg kunne have frygtet. Jeg er som de fleste andre ikke voldsomt imponeret over DSB's planlægningsevner, og oplever dermed fra tid til anden lidt frustrationer. Alt i alt har det alligevel været rimeligt problemfrit at skulle pendle. Det skal siges at jeg ikke pendler hver dag, og arbejder i toget når jeg gør - hvilket naturligtvis også hjælper en del.

Udover at skulle tilpasse mig livet som pendler var det også et skifte til en virksomhed der i langt højere grad arbejder med scrum og agile principper. Det har betydet en noget anden arbejdsgang end jeg var vant til, og jeg må helt klart tilskrive mig den voksende skare af folk der tilslutter sig disse principper.

Scrum har været med til at gøre det lettere at fokusere på det der er jobbet - at skrive software - samtidig med at det giver en dejlig ærlig tilgang til tingene. De gevinster føler jeg allerede i hverdagen, selvom vi ikke selv mener at vi er færdige med at indføre scrum - og bliver man egentlig nogensinde bliver det? Jeg har været til JAOO days om agile udvikling i København, og vores projektledere har er blevet certificerede scrum mastere. Så det er et område vi har fokus på, og det er derfor rart at mærke at investeringen giver afkast - i modsætning til de fleste andre investeringer, som verden ser ud for tiden.

Til den mere tekniske side har jeg haft mere fokus på TDD, DDD og CI - som man ikke kommer udenom som moderne agile udvikler. Uden at være modstander  har jeg altid været lidt skeptisk overfor TDD, men jeg må erkende at jeg er begyndt at mærke gevinsten i form af bedre design, og følelsen af frihed til at refaktorere. Vi holdt codecamp i ANUG regi i starten af marts ved min kollega Daniel Gonzáles Garcia, og det virker til at være et emne der har rimelig stor interesse i communitiet. Forhåbentligt lokker det flere til at begynde at arbejde med frameworks som ASP.NET MVC - som jeg selv er igang med :)

DDD tankegangen har altid været det der faldt mig naturligt, kontra databasetænkning som har en tendens til at bide en i røven når et system bliver tilstrækkeligt omfattende - og dermed uoverskueligt. At vi direkte har fokus på principperne giver en god fælles terminologi, og kombineret med brugen af et ORM gør det livet som udvikler en del sjovere.

CI er for mig noget nyt at skulle bruge i praksis, og én umiddelbar erfaring har været at det fjerner en hel del af smerten ved at skulle udgive webløsninger. Det meste der skrives om CI handler om at få afprøvet den samlede kodebase, og få afviklet sine unittests. Dette er naturligt også et hovedfokus - men det at gøre udgivelse til en mere naturlig del af processen skal bestemt ikke overses som en vigtig gevinst.

 

Tags: , , , ,

Gmail som spamfilter

by DotNetNerd 5. April 2009 14:51

Forleden nåede jeg punktet hvor jeg var ved at være for træt af mit mailsetup. Jeg havde kun et elendigt webinterface til at checke min private mail fra, samtidig med at spamfighter efterhånden ikke var godt nok på grund af mængden af spammails. Problemet er at jeg stadig skulle vente på at hive mails ned, idet de først bliver filtreret fra lokalt.

På kombineret anbefaling fra henholdsvis Søren Spelling Lund og Martin Strøm gjorde jeg derfor det at jeg satte min gmail konto til at trække mine mails ind fra mailserveren. På den måde kan jeg udnytte gmails spamfilter, og samtidig checke mails via gmails webinterface. Derudover satte jeg IMAP op på min gmail konto, så jeg stadig kan læse mine mails fra outlook og andre e-mail klienter. Det er super simpelt at gøre, og det hele kan administreres ved at logge ind på gmail og gå ind under "Settings" -> "Accounts" og "Forwarding and POP/IMAP".

Det er helt klart en anbefaling jeg vil give videre, da det fungerer rigtigt godt, ved at man får det bedste fra gmail uden at give afkald på fordelene ved at have sin egen mailserver med en mail adresse i eget domæne.

Tags:

SQL management studio og den dummeste feature ever

by DotNetNerd 25. March 2009 08:53

Jeg løb for nylig ind i at SQL Server 2008 management studio smed en exception da jeg prøvede at ændre et tabel design "Saving changes is not permitted. The changes require the following tables to be dropped and recreated..."

Først troede jeg det var NHibernate der havde låst tabellen, da den var genereret af NHibernate, men efter lidt søgning fandt jeg ud af at det var Microsoft der går hårdt efter titlen "dumbest feature of the year". Af en eller anden grund synes de som standard at det ikke skal være muligt at lave designændringer der kræver at tabellen droppes i 2008 udgaven af SQL manager.

 Idag løb en kollega så ind i samme problem, og dermed slog det mig at det nok var værd lige kort at skrive om her på bloggen, hvordan man slår det fra. Det er så enkelt som at gå ind under tools -> options og slå et flueben fra under punktet designers som det kan ses her:

 

Tags:

ViewData, reflectionbaseret typemapping og performance implikationer

by DotNetNerd 22. March 2009 13:17

Et sted jeg ofte oplever friktion imellem practices og frameworks er imellem godt objektorienteret design og webudviklings frameworks. Veldesignede objekter er sjældent specielt velegnede til f.eks databinding og serialisering. Eksempelvis kaster serialiseringsprocessen i MVC frameworket en exception, hvis man forsøger at serialisere et objekt der er del af en mange til mange relation (hvor to klasser har collections indeholdende instancer af hinandens typer). Det giver fint mening at det forholder sig sådan i en serialiseringskontekst, men omvendt kan man ikke i sit design undvære mange-til-mange relationer. I forhold til databinding kan det være et issue at man gerne vil databinde et objekt hvor nogle properties er komplekse typer, hvorfra der skal noget logik til at afgøre hvilken værdi der skal representere objektet i brugerfladen.

Løsningen på den slags udfordringer er ofte at lave en ViewData klasse der som udgangspunkt er et subset af den oprindelige klasse. Properties som er mere komplekse kan så fjernes eller ændres, og udregnede eller relaterede data kan tilføjes viewet. Som bekendt er der ingen designbeslutninger uden konsekvenser, og her er den tydelige konsekvens at man nu skal skrive kode til at mappe imellem entiteter og viewdata. I mange tilfælde er det virkelig trivielt, da properties navngives ens, så for at undgå at skulle gøre dette manuelt skrev jeg en MapToView metode.

public static ViewType MapToView<EntityType, ViewType>(EntityType entity) where ViewType : new()
{
    var view = new ViewType();

    var entityType = entity.GetType();
    var viewType = view.GetType();

    foreach(var property in entityType.GetProperties())
    {
        var viewProp = viewType.GetProperty(property.Name);
        if(viewProp != null && viewProp.PropertyType == property.PropertyType)
        {
            viewProp.SetValue(view, property.GetValue(entity, null), null);
        }
    }

    return view;
}

Den er naturligvis reflection baseret, og så siger ens barnelærdom jo at man skal passe på hvad det betyder for performance. En helt kort test hvor jeg har to klasser med 10 string properties som jeg mapper 1000 gange viste over 5 observationer at det tager ca. 53 gange så lang tid med MapToView frem for med manuel mapning. Det skal dog ses i det lys at vi snakker omkring 145 millisekunder på en 3,2 GHz Pentium 4 for de 1000 mapninger - så med mindre der virkelig er skarpe designkrav omkring performance vil det næppe være et issue.

Tags:

getJSON æøå gotcha

by DotNetNerd 19. March 2009 15:42

Idag løb jeg ind i en lille gotcha forbindelse med brug af JQuerys getJSON til at sende brugerinput til en MVC controller action. Problemet var at karaktererne æøå blev encoded i forbndelse med kaldet.

Efter uden held at have roddet med at ændre hvilken encoding JQuery bruger fik jeg et tip fra min kollega Morten Bock om at det kunne være fordi det (naturligvis) sendes via http get og dermed skulle urlencodes. Doh! Derfra tog det så ikke lang tid at finde ud af at der i javascript findes en escape funktion der gør netop det - og så var det blot at decode ved hjælp af Server.UrlDecode på serveren. 

Anyhow, håber hermed min erfaring kan være til nytte for andre der løber ind i samme problem.

Tags:

JQuery Ajax debugging

by DotNetNerd 9. March 2009 20:36

Jeg løb fornylig ind i at jeg ville lave et ajax kald ved hjælp af JQuery og $.getJSON, men min action blev aldrig ramt og der blev ikke kastet nogen exceptions. Det viser sig at skyldes at getJSON forsøger at lave kaldet, men hvis det fejler ignorerer den det blot. Løsningen er at for at kunne debugge skal man istedet bruge $.ajax, som gør det muligt at registrere en errorhandler. Herfra kan man så tilgå det response der returneres, og hvis man udskriver det til siden får man en overraskende god fejlside, der gør det nemt at debugge.

Det var ikke et trick jeg fandt beskrevet nogen steder, så jeg synes det var værd at dele - og så er det ellers en af den slags posts jeg tror jeg selv bliver glad for næste gang jeg skal bruge den her lille snippet :-)

$.ajax(
{
    type: "GET",
    url: "/Controller/Action",
    data: { registrationTypeId: selectedValue },
    dataType: "json",
    error: function(xhr, status, error) {
        document.write(xhr.responseText);
    }, success: function(json) {
        alert("Data Returned: " + json);
    }
});

Tags: ,

xVal - fin løsning på klassisk problemstilling

by DotNetNerd 3. March 2009 17:11

Noget så basalt som validering der på overfladen virker som en simpel ting har alligvel en tendens til at ende med at ende med at blive uskønt i webløsninger. Der er to problemer jeg tit har set når jeg har kigget både mine egne og andres projekter igennem.

  1. Man bør implementere sin validering både client- og serverside. Dette fører til at man bryder DRY princippet, og laver valideringen dobbelt i henholdsvis javascript og ens eget CLR language of choise.
  2. Om noget er validt er i høj grad afhængig af kontekst  - se who knew domain validation was so hard .

Især punkt 1 er tit en tjørn i øjet på webudviklere, da de færreste synes det er sjovt at lave validering. Ligefrem at skulle gøre det samme to gange kan derfor være en pain - især når det så senere skal vedligeholdes.

Her kommer xVal til undsætning hvis man arbejder med ASP.NET MVC, da det gør det muligt at udtrykke sin validering ved hjælp af attributter man angiver på properties på sine entiteter. Samtidig gør det at man får flyttet sin validering ned i modellen, hvor man gerne vil have den.  Jeg vil undlade at komme med eksempler, da Steve Sanderson allerede har lavet nogle gode eksempler på sin blog. En stor bonus ved frameworket der fortjener at blive nævnt er at det er meget fleksibelt, både i forhold til valg af framework til clientside validering, og når man ønsker at implementere sine egne custom valideringer.

I forhold til punkt 2 bryder xVal umiddelbart med princippet om ikke at ligge valideringen på sine entiteter. Jeg vil imidlertid spille gråzone kortet, idet selve det at foretage valideringen er noget man styrer server- og clientside. Det er dermed helt muligt at lave andre typer af validering også, og anvende xVal specifikt til at validere brugerinput fra formularer.

 

Tags:

Who am I?

My name is Christian Holm Diget, and I work as an independent consultant, in Denmark, where I write code, give advice on architecture and help with training. On the side I get to do a bit of speaking and help with miscellaneous community events.

Some of my primary focus areas are code quality, programming languages and using new technologies to provide value.

Microsoft Certified Professional Developer

Microsoft Most Valuable Professional

Month List

bedava tv izle