Når man arbejder med relationelle databaser i moderne softwareudvikling, er det vigtigt at forstå, hvordan man konfigurerer og arbejder med forskellige type inheritance-mapping-strategier i Entity Framework Core. TPH (Table Per Hierarchy), TPT (Table Per Type) og TPC (Table Per Concrete Type) er tre hovedmetoder, der bruges til at mappe objekthierarkier til relationelle tabeller i en database. Hver af disse strategier har sine egne fordele og ulemper, som afhænger af applikationens krav og design.
Når man arbejder med databaser i .NET, bruges ofte en konkret implementering af Entity Framework Core (EF Core), som giver mulighed for at mappe objektorienterede klasser til relationelle tabeller. EF Core håndterer de underliggende SQL-forespørgsler, hvilket gør det muligt at arbejde med objektmodeller på et højt niveau uden at bekymre sig om de detaljerede SQL-kommandoer, der bliver genereret.
Den første tilgang er TPH (Table Per Hierarchy). I TPH-strategien gemmes alle data for en klassehierarki i én enkelt tabel. Dette betyder, at både de fælles og de specifikke egenskaber for hver underklasse placeres i én tabel. Tabellen får ekstra kolonner, som bruges til at identificere, hvilken underklasse rækken tilhører. Fordelen ved denne metode er, at den giver en enkel struktur og hurtigt kan håndtere queries på tværs af hierarkiet. Ulempen er, at man risikerer at have mange null-værdier i tabellen, hvis ikke alle underklasserne har brug for alle kolonner.
Når man bruger TPT (Table Per Type), oprettes der separate tabeller for hver type i hierarkiet. Hver tabel indeholder kun de specifikke egenskaber for den pågældende type, og der er en relation (ofte via en fremmednøgle) til den overordnede tabel. Denne metode kan føre til mere normaliserede databaser, da hver tabel kun indeholder de relevante kolonner. Dog kan queries blive mere komplekse, da flere tabeller skal sammenkobles, når man henter data på tværs af hierarkiet.
TPC (Table Per Concrete Type) adskiller sig fra både TPH og TPT, da hver konkret klasse får sin egen tabel, og der oprettes ikke en separat tabel for den overordnede klasse. Dette betyder, at tabellerne kun indeholder data for de specifikke underklasser og ikke for hele hierarkiet. Denne tilgang kan give den bedste ydeevne, da den undgår unødvendige joins, men den resulterer også i et større antal tabeller, hvilket kan blive svært at håndtere i større applikationer.
Når man arbejder med en af disse strategier, er det vigtigt at forstå, hvordan de interagerer med SQL-databasen og hvilke konsekvenser de har for ydeevnen. For eksempel, i TPH, vil du kunne hente data med færre joins, men du skal muligvis håndtere flere null-værdier. I TPT kan databasen blive mere normaliseret, men det kan kræve flere kompleksiteter ved sammenkobling af tabeller. TPC er ofte den mest effektive i forhold til ydeevne, men det kan føre til redundans, da data for underklasserne ikke deles i tabellerne.
En praktisk applikation af disse teknikker kan ses i eksemplet med en konsolapplikation, hvor vi arbejder med en database med tabellen 'People'. Ved brug af TPH oprettes der én tabel til alle typer personer, og man kan se en simpel liste af personer med deres ID og navn. Når vi skifter til TPT, ser vi, at databasen opretter separate tabeller for 'Students' og 'Employees', hvilket muliggør en mere præcis opbevaring af data for hver type person. I tilfælde af TPC vil vi opleve, at der er færre tabeller, men hver tabel vil kun indeholde data for en konkret type.
I praksis vil man ofte vælge den strategi, der passer bedst til den specifikke applikation og databasens designkrav. Hvis man har behov for hurtige forespørgsler og mindre kompleksitet, kan TPH være den rigtige løsning. Hvis normalisering er en prioritet, kan TPT være den bedste tilgang. Hvis ydeevne er kritisk, kan TPC tilbyde en effektiv løsning.
Det er også vigtigt at forstå, hvordan disse strategier spiller sammen med andre vigtige funktioner i EF Core, såsom sekvenser og standardværdier. For eksempel kan man konfigurere en sekvens til at generere entydige ID'er for personer, hvilket sikrer, at ID'erne ikke overlapper, selvom flere typer personer oprettes i forskellige tabeller.
Når du arbejder med databaser og objektorienteret programmering, er det vigtigt at forstå de grundlæggende principper bag objekt-relationel mapping (ORM), især når du arbejder med en kompleks datamodel. EF Core giver en fleksibel og kraftfuld måde at arbejde med relationelle databaser på, men det kræver en god forståelse af, hvordan data bliver struktureret og gemt i databasen. Uanset om du vælger TPH, TPT eller TPC, vil det at vælge den rette strategi være afgørende for applikationens ydeevne og vedligeholdelse.
Hvordan Async/Await Forbedrer Responsiviteten i GUI Applikationer
Når vi arbejder med programmering i C#, spiller begreberne synkron og asynkron udførelse en stor rolle i, hvordan applikationer håndterer opgaver som databasetilslutninger eller netværksanmodninger. C#-kompilatoren skaber en kompleks tilstandsmaskine og holder styr på de kørende tråde. Dette er en noget magisk proces, hvor kombinationen af de to nøgler 'async' og 'await' gør det muligt for metoder at køre på en baggrundstråd og derefter returnere resultaterne til brugergrænsefladen (UI-tråden), når de er færdige.
For at illustrere dette i praksis, lad os tage et eksempel, hvor vi bygger en Windows desktop applikation ved hjælp af WPF. Formålet er at hente medarbejdere fra Northwind-databasen, som findes i en SQL Server-database, ved hjælp af lavniveau-typer som SqlConnection, SqlCommand og SqlDataReader. Northwind-databasen er moderat kompleks og indeholder et betydeligt antal eksempelposter, og den blev introduceret i kapitel 2 af denne bog, hvor den blev sat op.
For dette eksempel skal du være opmærksom på, at du kun kan gennemføre opgaven, hvis du har Microsoft Windows og Northwind-databasen opbevaret i Microsoft SQL Server. Dette afsnit er derfor ikke cross-platform og moderne, da WPF (Windows Presentation Foundation) er 17 år gammel. For at bygge applikationen kan du vælge at bruge enten Visual Studio 2022 eller Visual Studio Code. Selvom vi ikke dykker ned i XAML og kryds-platform udvikling i denne sektion, er det en god mulighed for at få et indtryk af, hvordan en WPF-applikation kan bygges.
Eksemplet: Synkron vs. Asynkron Datahentning
-
Opret et nyt WPF-projekt kaldet "WpfResponsive" i Visual Studio 2022 (eller brug Visual Studio Code med
dotnet new wpf). -
Tilføj en pakke-referencen
Microsoft.Data.SqlClienttil projektet. -
Sørg for, at projektfilen er korrekt konfigureret til Windows EXE, .NET 7, og WPF.
Nu er vi klar til at tilføje funktionalitet til applikationen. I MainWindow.xaml skaber vi et simpelt layout med to knapper, en tekstboks og en listeboks, som alle er organiseret i en stack panel. De to knapper vil enten hente medarbejdere synkront eller asynkront.
Synkron metode
Den synkrone version åbner forbindelsen, henter medarbejderdata og fylder listeboksen. Dette gøres ved hjælp af de standard synkrone metoder til SQL-forbindelse og datahentning. Når brugeren klikker på "Get Employees Synchronously"-knappen, bliver brugergrænsefladen (UI) låst, mens dataene hentes, hvilket betyder, at brugeren ikke kan interagere med applikationen, før operationen er afsluttet.
Asynkron metode
Den asynkrone version af metoden bruger async og await til at åbne forbindelsen og hente medarbejderne uden at blokere UI-tråden. Brugergrænsefladen forbliver responsiv, hvilket betyder, at brugeren kan interagere med applikationen, mens dataene hentes i baggrunden.
For at skabe de to event-håndterere, der svarer på knaptryk, definerer vi et synkront og et asynkront event:
-
GetEmployeesSyncButton_Click: Henter medarbejdere synkront, hvilket resulterer i, at UI er låst under datahentningen. -
GetEmployeesAsyncButton_Click: Henter medarbejdere asynkront, og holder UI-tråden responsiv under hele processen.
I begge tilfælde bruges en Stopwatch til at måle, hvor lang tid datahentningen tager, og denne tid bliver tilføjet til listeboksen som en tidsmåling, der viser forskellen mellem de synkrone og asynkrone metoder.
Forskel på Synkron og Asynkron Udførelse
Når du kører applikationen, vil du bemærke en markant forskel i brugeroplevelsen mellem de to metoder:
-
Når du bruger den synkrone metode, vil GUI'en blive blokkeret i de 5 sekunder, som databasetransaktionen tager, og du vil ikke kunne interagere med applikationen i denne periode.
-
Når du bruger den asynkrone metode, vil GUI'en forblive responsiv, og du kan fortsætte med at indtaste tekst i tekstboksen, selvom dataene stadig hentes.
Dette er et vigtigt aspekt af moderne applikationsdesign, hvor asynkrone operationer kan gøre applikationer mere brugervenlige, især når der arbejdes med langsom datatilgængelighed eller komplekse beregninger.
Skalering af Webapplikationer og Webtjenester
Async og await kan også anvendes på serversiden ved opbygning af websteder, applikationer og webtjenester. Set fra klientapplikationens synspunkt ændrer der sig ikke meget, eller de vil måske endda opleve en lille stigning i den tid, det tager for en anmodning at blive besvaret. Når dataene hentes fra serveren, kan den asynkrone proces sikre, at serverens ressourcer ikke bliver overbelastet, da det tillader, at flere anmodninger kan behandles samtidig uden at vente på, at hver enkelt bliver afsluttet.
Dette betyder, at webapplikationer, der bruger asynkrone metoder, kan håndtere mange samtidige anmodninger effektivt, hvilket forbedrer både serverens ydeevne og slutbrugerens oplevelse.
Det er vigtigt at forstå, at selvom asynkrone metoder som async og await kan forbedre responstiden og brugervenligheden af applikationer, så kræver de en nøje overvejelse af, hvordan applikationens tråde og ressourcer håndteres. Asynkrone metoder giver ikke nødvendigvis en hurtigere behandling af opgaver, men de forbedrer applikationens evne til at håndtere flere opgaver samtidigt uden at blokere brugergrænsefladen eller serverressourcer.

Deutsch
Francais
Nederlands
Svenska
Norsk
Dansk
Suomi
Espanol
Italiano
Portugues
Magyar
Polski
Cestina
Русский