Repository design med LINQ – querying

by DotNetNerd 23. May 2009 18:38

Linq implementationer rettet imod databaser har gjort der nemt tilgængeligt at anvende lazy loading og at opbygge querys via komposition. “With great power comes great responsibility” fristes jeg til at skrive, da den meget integrerede brug af lazy loading gør at man skal huske selv at overveje hvornår querys skal omsættes til SQL og afvikles imod databasen. Det har udviklet sig til et best practice råd i MVChvor det direkte bryder med MVC mønstret idet man flytter logik til viewet – hvilket naturligvis kan være et lige så stort problem i andre framework.

I forlængelse af diskussionen omkring hvornår querys afvikles giver Linq anledning til at overveje hvordan man vil indkapsle sine querys? Den før omtalte Repository is dead: Long live repositoryblogpost omhandler netop diskussionen om man skal have en metode pr query eller om selve filtreringen er et argument der passes til metoder som T FindOne(Expression<Func<T, bool>> expression). Kort og sagt med andre ord er argumenterne for hver indkapsling vs Open Close Principle.

Indkapsling og dermed også genbrug af querys anser jeg ihvertflad som vigtigt, men der er andre måder at gøre det på end ved at lave et repository med “en metode pr. query”. Den første tanke er tit at man kan lave en service ovenpå sine repositories som indeholder querylogikken. Det vil imidlertid betyde at en sådan service blot bliver et gennemstillingslag for simple querys – og det er kode jeg ikke kender nogen der synes er sjovt at skrive.

Filtre som extention methods en elegant måde at skrive querys der kan genanvendes og skabes via komposition ved hjælp af piping f,eks new Repository<Customer>().FindAll().WithAddress(adr).WithNumberOfChildren(2); Som altid er der imidlertid “no such thing as a free dinner”, da det ikke sikrer at querys bliver afviklet. Her er min konklusion indtil videre at jeg vil vise tilbage til den tidligere nævnte best practice, og lade det være udviklerens ansvar.

 

Tags:

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: , ,

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