Presentasjon lastes. Vennligst vent

Presentasjon lastes. Vennligst vent

Redusere kompleksitet i Entity Framework spørringer Skrevet av Tore Aurstad, 23.11.2014 1.

Liknende presentasjoner


Presentasjon om: "Redusere kompleksitet i Entity Framework spørringer Skrevet av Tore Aurstad, 23.11.2014 1."— Utskrift av presentasjonen:

1 Redusere kompleksitet i Entity Framework spørringer Skrevet av Tore Aurstad,

2 Redusering av kompleksitet i EF- spørringer En utfordring med Entity Framework er at spørringer i produksjonskode blir kompleks rett og slett fordi det er nødvendig. Det som ikke er nødvendig er å beholde all kode for EF- spørringer i en enkelt, monolittisk metode og spørring. Ulike teknikker for å dekomponere, forenkle og refaktorere EF- kode for å forenkle EF-spørringer vil presenteres her. 2

3 Chaining av EF-spørringer med IQueryable [1/3] Reduksjon av kompleksitet i EF-spørringer er mulig ved å tilby filtermetoder på entiteter som returnerer IQueryable av type T. Det er mulig å chaine slike filtermetoder. Metodene man lager bør være static for å støtte dette. Eksempel: private static IQueryable GetOperationsQueryableWithTracking(IOpPlanDataContext context, OperationsRequestDataContract request, int status, bool isOperationScheduleStatus) { var operations = context.Operations.Where(o => (isOperationScheduleStatus ? context.TheaterOperationalUnitLinks.Any(x => x.FreshOrganizationalUnitId == requ est.FreshId && x.TheaterId == o.TheaterId) : o.OperationalUnitId == request.FreshId) && (o.Status != (int)OperationStatusDataContract.None && ((status & o.Status) == o.Status)) || (request.AllowStatusSetToNone && request.Status == OperationStatusDataContract.None)); operations = FilterByTheaterId(request, operations); operations = FilterByOperatingDate(request, operations); return operations; } 3

4 Chaining av EF-spørringer med IQueryable [2/3] private static IQueryable FilterByTheaterId( OperationsRequestDataContract request, IQueryable operations) { if (request.TheaterIds != null && request.TheaterIds.Count() > 0) { operations = operations.Where(o => request.TheaterIds.Contains(o.TheaterId)); } return operations; } private static IQueryable FilterByOperatingDate(OperationsRequestDataContract request, IQueryable operations) { if (request.FromOperatingDate.HasValue && request.ToOperatingDate.HasValue) { var fromDate = request.FromOperatingDate.Value.StartOfDay(); var toDate = request.ToOperatingDate.Value.EndOfDay(); operations = operations.Where(o => (o.OperatingDate >= fromDate && o.OperatingDate <= toDate) || o.Status == (int)OperationStatusDataContract.Urgent); } return operations; } 4

5 Chaining av EF-spørringer med IQueryable Bemerk at når man filtrer en entitet på denne måten gjentatte ganger blir ikke spørringer kjørt umiddelbart. Akkurat som i LINQ to Objects så er det slik i EF, som har dialekten LINQ to Entities, ikke en kjøring av spørringene før man enumerer spørringene. En slik enumerering skjer typisk når man brukes ToList(), ToArray(), ToDictionary() eller gjør en foreach. Hvis man har en kompleks spørring kan man gjør ulike filtreringer for å forenkle den komplekse spørringen. I spørringen i dette eksempelet er det mulig å refaktorere videre ved å flytte et av predikatene ut til en egen metode. LINQ to Entities forbyr metodekall inne i selve spørringene, men det er likevel mulig med å bruke LinqKit 5

6 Linqkit Med LinqKit kan man bruke metodekall inne i query syntaxen til spørringer. Dette gjør det mulig å gjenbruke funksjonalitet i EF, akkurat som filtreringsmetoder som returnerer IQueryable. LinqKit er tilgjengelig som NuGet pakke og kan installeres enkelt i en Visual Studio løsning: Install-Package LinqKit I stedet for å returnere IQueryable, vil metodene man legger til hvor man skiller ut logikk i egen predikatmetode returnere Expression >. Linqkit har mer funksjonalitet enn det som presenteres her. Linqkit er laget av Joseph Albahari, som også har laget LinqPad. Linqpad er nyttig for å jobbe med EF spørringer. Det reduserer debug syklusen og lar en også se SQL-en som genereres av EF. Det er også mulig å jobbe med LinqKit inne i Linqpad. 6

7 Eksempel på spørring i LinqPad som bruker LinqKit inne i LinqPad private Expression > IsOperationInSharedTheaterOrOwned(int freshId) { var predicate = PredicateBuilder.False (); predicate = predicate.Or(o => (o.OperationalUnitId == freshId) || (TheaterOperationalUnitLinks.Any(tou => tou.FreshOrganizationalUnitId == freshId && tou.TheaterId == o.TheaterId) && o.Theater.OperationalUnits.Any(tou => tou.FreshOrganizationalUnitId == freshId))); return predicate; } void Main() { var startTimeWindow = new DateTime(2014,5, 24).StartOfDay(); var endTimeWindow = new DateTime(2014,5, 24).EndOfDay(); var currentOperationalUnitFreshId = ; var operations = from operation in Operations.AsExpandable().Where(IsOperationInSharedTheaterOrOwned(currentOperationalUnitFreshId)) where operation.Status != (int)OperationStatusDataContract.Deleted && operation.OperatingDate >= startTimeWindow && operation.OperatingDate <= endTimeWindow from patient in Patients where patient.OperationId == operation.OperationId select new { operation.OperationId, operation.Status, operation.OperatingDate, patient.Name,patient.OfficialId}; operations.Dump(); } 7

8 Eksempel på spørring i Linqpad som bruker Linqkit I spørringen i eksempelet så benyttes metoden.AsExpandable() slik at man kan benytte Linqkit sine utvidelsesmuligheter som muliggjør metodekall inne i query syntaxen. Metoden man kaller bruker Where og selve metoden, som returnerer Expression >. I tillegg benyttes PredicateBuilder i Linqkit som initielt settes til false. Nå kan man inne i metoden bruke.Or() metoden i Linqkit og implementere predikatet. Linqkit kan brukes i Linqpad ved å legge til en referanse til Linqkit.dll- en og navnerommet Linqkit. Kryss også bort Include Predicatebuilder i Linqpad options (F4). I kodeeksemplet så er koden kjørt inne i LinqPad. Her er context implisitt og ikke i koden. I tillegg så vil metoden for predikatet være static i produksjonskode, men i Linqpad er det ikke static modifier her. Dump() metoden i Linqpad sender resultatet ut i GUI-et til Linqpad. 8

9 Linqpad skjermbilde 9

10 Linqpad og SQL-visning 10

11 Oppsummering Entity Framework har støtte for å dekomponere spørringer ved å returnere IQueryable i spørringer. Når man returnerer IQueryable kjører ikke spørringene før man enumerer resultatet, altså ikke umiddelbart. Med Linqkit kan man flytte kode i EF-spørringer ut i egne metoder og gjenbruke funksjonalitet. Ofte så vil man ende opp med monolittisk kode i Entity Framework hvor mye logikk skrives, som i for eksempel rapportspørringer. I denne presentasjon har det blitt presentert to ulike teknikker som lar en gjenbruke kode i EF, noe som både lar en redusere kompleksiteten, men også raskere lage funksjonalitet, ved gjenbruk i seg selv. 11

12 Separation of Concern Husk at en metode skal i utgangspunktet gjøre kun en ting! Med de to teknikkene presentert her kan man i alle fall redusere kompleksiteten. Veldig mye av koden man skriver i Hemit er faktisk i datalaget og sjonglering logikk på entieter i Entity Framework. Jo bedre man blir til å kode EF, jo mindre kåbåikode ender man opp med og jo enklere blir vedlikeholdet, samt lesbarheten i koden økes. En EF-metode som knapt får plass på en A4 side er ikke uvanlige i løsninger. Ofte skriver man også den samme koden igjen, fordi vanlig EF ikke tillater metodekall inne i queryen, men med Linqkit er det lov. EF kode kan ofte brukes feil. Bruk gjerne Linqpad og sjekk at spørringene man lager ikke kjører tregt eller henter ut mye data. SQL Server Profiler er også nyttig verktøy. 12

13 That’s all folks! 13


Laste ned ppt "Redusere kompleksitet i Entity Framework spørringer Skrevet av Tore Aurstad, 23.11.2014 1."

Liknende presentasjoner


Annonser fra Google