Data Containere - lean or mean

by DotNetNerd 25. October 2007 17:45

Datacontainere - kort fortalt

I .NET findes der flere forskellige datacontainere som DataSet, Strongly typed DataSet og XmlDocument. Disse containere kan man bruge "lige ud af boksen" hvis man skulle have lyst til det, men man kan også vælge enten at lave en wrapper der arbejder på en af disse typer eller også man kan lave sine egne custom entiteter.

Hvilken container man ender med at bruge i sin applikation er oftest afgjort ud fra personlig præference og funktionelle krav til applikationen man er ved at udvikle. Da valget af containere er meget centralt i designet af en applikation mener jeg det er vigtigt at man ved hvilke konsekvenser valget har for udviklingstiden og for det overordnede design.

Det jeg vil se på i den her artikel er hvordan man vælger den "bedste" container til sin applikation og hvilke fordele og ulemper et sådan valg fører med sig.

Hvordan vælger jeg hvilken der passer bedst til min applikation?

Hvilken datacontainer der er "best" findes der ikke noget entydigt svar på, da de alle har deres fordele og ulemper. For at kunne vælge den rette datacontainer til sin applikation har jeg valgt 3 faktorer jeg vil fokusere på:

  • Design kriterier
  • Udviklingstid/levetid
  • Funktionelle krav

Design kriterier

Inden man begynder at træffe beslutninger omkring design er det altid vigtigt (ikke kun ved valg af datacontainer) at opstille nogle design kriterier, som man kan vurdere forskellige løsninger udfra. Ofte vælger man nogle begreber som er centrale for ens design, eller også tager man en fast liste af begreber og vurderer hvilke der er vigtigst for det aktuelle design. Herunder er en liste over begreber, der er relevante ved valg af datacontainere, som man typisk kan bruge til at beskrive designkriterier.

Skalerbart - skal det være muligt at skalere applikationen så den f.eks ligger på flere servere?

Genbrugbart - skal dele af applikationen kunne genbruges i andre lignende applikationer?

Integrerbart - skal applikationen integreres med andre applikationer?

Performance - er der nogen krav til hvor hurtigt en given funktion skal afvikles?

Fleksibelt - er der nogen krav til at systemet skal kunne ændres når det er taget i brug?


Funktionelle krav

Udover de generelle designkriterier kan man se på de funktionelle krav der stilles til applikationen. Skal data kunne konverteres til xml? Skal det være muligt at lave sortering? Skal data distribueres? Hvis ja, skal de så kun distribueres ud til ens egne applikationer eller også til kunder? Skal de distribueres via en webservice eller via remoting i et client/server scenarie?

Alle disse typer overvejelser er relevante for valget af datacontainer. Et Dataset kan f.eks konverteres til xml og understøtter sortering samtidig med det er en type webservices genkender og kan genskabe hos klienten. På den anden hånd kan et dataset ikke udvides med ekstra funktionalitet, og det er ikke typestærkt, hvilket kan lede til uskøn kode hvis man skal lave mange metoder til at arbejde med data som måske ligefrem bliver nød til at findes i flere lag af ens applikation.

Hvis du bruger et strongly typed dataset bliver det godt nok typestærkt, men det er stadig ikke muligt at tilføje egne funktioner, og det er mindre generisk end "lillebror".

Custom entiteter giver mulighed for at tilføje funktionalitet, men lider under den sygdom at funktionerne ikke sendes med over en webservice. Tilgengæld kan de skræddersyes så du får præcist den funktionalitet du drømmer om, og du kan distribuere denne funktionalitet ud til en klient via remoting. Overvejelserne er mange men de bør gennemtænkes for den enkelte applikation da de er meget væsentlige, og har stor betydning for hvordan de funktioner man skal udvikle kan udformes.


Udviklingstid/levetid

Sidst men bestemt ikke mindst kommer den faktor som din kunde, projektleder eller chef nok går rigtigt meget op i, og som du selv ville ønske ikke var så væsentlig. Det kan være enormt fristende at give sig i kast med at udvikle custom entiteter, da de giver maksimal frihed, men det kræver ekstra udviklingstid og er dermed til at fordyre applikationen. Derfor skal valget af custom entiteter ofte være begrundet i at det kan forlænge en applikations levetid igennem øgedet fleksibilitet eller at det giver nogle muligheder som man ikke har ved at bruge DataSet, XmlDocument eller lignende.


Forskellige datacontainere og deres datastruktur

Når man har vurderet design kriterier, funktionelle krav og udviklingstid kan man se på hvilken type datacontainer der er mest velegnet til applikationen. I nogen typer applikationer viser der sig måske ligefrem at det bedste resultat er at bruge en type container til nogle specifikke moduler, og en anden container til andre moduler.

For at kunne vælge må vi se på hvilke fordele og ulemper der er forbundet med de forskellige datacontainere. Jeg vil her gå lidt mere i dybden med den mest gængse.

  • DataSet
  • Strongly typed DataSet
  • Custom entitet
  • XmlDocument
  • XmlDataDocument

Disse datacontainere kan deles ind i 3 kategorier efter hvordan data struktureres.
Der findes de relationelle datastrukturer, som DataSet og Strongly typed DataSet, der er bygget på samme måde som en databasestruktur, med tabeller, keys og relationer.
Custom entiteter er objekt-orienterede så de indeholder typer og collections det kan bygges op i en hirakisk struktur.
Og den sidste kategori XmlDokumenter arbejder som navnet antyder med Xml som er hirakisk opbyggede tags.

Relationelle og objekt-orienterede datastrukturer er normalt dem man vælger imellem når man skal udvikle en rigtig enterprise applikation, da dette er et stort emne er set et afsnit helt for sig selv.
XmlDokumenter bruges til at løse specifikke problemstillinger, hvor man ikke ønsker at have data liggende i en database. Xml er f.eks godt til at beskrive et sitemap eller til at strukturere tekster og billeder så man slipper for at de ligger og roder i databasen.

XmlDocument klassen giver mulighed for at arbejde effektivt med data i et XMl format. Dette gøres ved hjælp af XPath queries, som der findes en hel seperat artikel om her på sitet :-)

En lidt finurlig kombination af to verdener finder man i XmlDataDocument klassen. Denne klasse kombinerer, som man måske kan gætte, brugen af DataSet og XmlDocument. Det vil sige at man kan få det bedste af funktionaliteten ved at bruge XmlDocument til rådighed så det kan bruges til at arbejde med et DataSet ved at lave et XmlDataDocument der arbejder på DataSettet. Det vil være fordyrende at sende et XmlDataDocument fra lag til lag i en applikation. Man vil derfor oftest nøjes med at sende DataSettet, og så oprette sit XmlDataDocument (der kan ses som en slags wrapper) når man har brug for denne udvidede funktionalitet.


Strulturelt vs Objekt-Orienteret

Valget imellem relationelle og objekt-orienterede datastrukturer har efterhånden udviklet sig til en hel religionskrig, som jeg vil prøve så vidt muligt at holde mig fri af. Det er imidlertid nødvendigt lige at knytte et par kommentarer til emnet.
Overordnet set er det muligt at løse de samme problemer med begge typer datastrukturer, den store forskel ligger omkring abstraktionsniveauet.

Relationelle datastrukturer afspejler databasen de anvendes oven på, hvilket nogen vil argumentere for er et problem, da man derved ikke får abstraheret databasens opbygning bort og eventuelle ændringer vil forplante sig ud i applikationen.

Objekt-orienterede strukturer derimod afspejler virkelige objekter og modeleres efter udviklerens ønsker. Dette giver ganske vidst en bedre abstraktion, således at strukturelle ændringer i databasen kun medfører ændringer i de metoder der sørger for at mappe data imellem databasen og objekterne. Ulempen ved denne fremgangsmøde er tilgengæld at strukturen tit kommer til at minde om tabeller alligevel. Dette skyldes at objekterne oftest ender med at blive sendt til en brugergrænseflade hvor de skal databindes - og denne process kræver et tabulart format. Med andre ord ser man tit at klasser ender med at beskrive kolonner via properties, og da de enkelte objekter bliver så til rækkerhvor collections så svarer til en tabel.

Prøver man bevidst på at bygge en hirakisk domæne model løber man hurtigt ind i bøvl når der skal databindes og man ender med at skrive en ordentlig bunke løkker til at finde et givent objekt i en collection. Selvom det måske kan lyde uskyldigt nok har det den sideeffekt at jo flere niveauer du har i dit hiraki, jo flere løkker har du inden i hinanden, hvilket er virkelig skidt for performance. Tænk f.eks på hvad det vil kræve for at kunne finde en medarbejder i en afdeling i en virksomhed. Egentlig et simpelt eksempel som sagtens kunne blive værre (virksomheden kunne være i en by som kunne være i en kommune i et land!), men allerede her vil man typisk skrive 3 løkker inden i hinaden således at man for hver virksomhed checker alle afdelingers medarbejdere.
Alternativet er naturligvis at skrive nogle metoder i sit data access lag som kan hente mindre dele af strukturen ud. Dette er imidlertid heller ikke altid det man ønsker, da det vil betyde at man skal skrive rigtigt mange lavniveau metoder for at kunne søge efter specifikke objekter - hvilket også kan have en effekt på helt ens design efterhånden som man har en overflod af metoder.

Designer man sin objekt struktur så flad som muligt kan der imidlertid godt være noget hentet i at man kan abstrahere databasen bort og indkapsle mapningen i sit eget data access lag. Dette kan imidlertid også godt gøres ved hjælp af f.eks et DataSet, da det strengt taget ikke behøver ligne den underliggende database - men det fungerer helt klart bedst hvis det gør.

Personligt står jeg med et ben i hver lejr, da jeg mener det er helt an på hvad man er ved at udvikle. Pointen med denne diskussion er derfor ikke at komme med en afgørelse, men derimod blot at gøre opmærksom på at der er disse 2 måder at "se verden på" og at forklare de fordele og ulemper der er forbundet med dem hver især.


Wrappere

Ved at bruge wrappere som f.eks indkapsler et DataSet eller et XmlDataDocumentkan kan tilføje alt den ekstra funktionalitet man kan tænke sig. Det giver samtidig mulighed for at trække på den eksisterende funktionalitet som der wrappede objekt har. Man betaler imidlertid den pris at man skal bryde indkapslingen hvis funktionerne skal tilgås udefra. Wrappere er desude med til at tilføre ekstra overhead, hvilket kan være et problem hvis der skal instantieres mange objekter af typen.

Den mest oplagte klasse at wrappe er nok DataSet, da det kan indeholder hvad som helst og man derved kan lave generisk funktionalitet som kan bruges på et hvilket som helst datagrundlag. XmlDataDocument er et eksempel på en wrapper der pakker et DataSet ind i XmlDocument funktionalitet.


Fordele og ulemper

Til sidst vil jeg se mere konkret på de enkelte klasser og beskrive deres fordele og ulemper. Herved håber jeg at ende med en liste som, når man har læst ovenstående, kan bruges til at træffe et fornuftigt og velovervejet valg af datacontainer.

DataSet

Har funktionalitet til at sortere, søge, filtrere i data og til at konvertere til xml.

Er meget fleksibelt, da det er generisk og data beskrives via schema information.

Kan sendes over en webservice og være fuldt funktionelt på klienten.

Skal fyldes med schema information som kan gøres på 3 måder:

  • Manuelt ved at lave et lag der sørger for at hælde data i dine DataSet.
  • Ved at læse schema information fra en XSD via ReadXmlSchema metoden.
  • Ved at hende schema information fra databsen ved hjælp af DataAdapterens FillSchema metode - dette er dog meget tungt og bør bruges med omhu.
Bruger meget hukommelse hvis man kun skal hente en enkelt række.

Strongly typed DataSet

Har samme funktionalitet som DataSet til sortering, søgning, filtrering og xml konvertering.

Er typestærkt og giver derved kønnere kode der er lettere at skrive.

Indeholder schema information som beskrives på design tidspunktet.

Klienter der henter via webservice får kopi af schema information og mister ikke funktionalitet.

Kan forbedre hastighed i forhold til et almindeligt DataSet da peopertys kalder via index.

Skal regenereres ved strukturændringer.

Større overhead than dataset.

Der er mange scenarier hvor det ikke er helt har den funktionalitet man ønsker sig.

Custom entities

Giver fuld fleksibilitet i forhold til funktionalitet.

Minimalt interface der kun stiller der til rådighed man ønsker.

Kan enten være intelligente, helt dumme (Data Transfer Objekter) eller midt imellem.

Logik kan distribueres imellem lag og imellem klienter.

Der er kun properties der sendes med over webservice, så klienten har ikke gavn af metoder og attributter.

På trods af den Objekt-Orienterede natur vil strukturen oftest ende med at ligne en tabel, af hensyn til databinding.

Indeholder ingen funktionalitet til søgning og denne kan være omfattende og problematisk ved uheldigt strukturelt design.

God performance ved få entiteter, men taber i forhold til DataSet ved store datamængder.

XmlDocument

Stærkt til at beskrive hirakiske data.

Data kan gemmes eksternt i filer og kræver ikke database eller lignende persistensmedie.

Datatilgang via query sprog.

Er ikke typestærkt.

Fladt format, da det basalt set er tekst.

Tendens til at blive rodet og tungt ved store mængder komplekse data.

XmlDataDocument

Kombinerer funktionaliteten fra DataSet og XmlDocument.

Data kan gemmes i database eller som XML.

Søgning kan laves både via Xpath queries og direkte tilgang til DataSet.

Kan anvendes efter behov og behøves ikke sendes med ved distrubution, hvor man enten sender Xml eller DataSet alene.

Kan føre til uklar kode og struktur ved blanding af XPath queries og datatilgang via DataSet.

Idet objektet består af DataSet og XmlDokument bliver objektet tungere end de to typer er hver især.

DataSet Wrapper

Man kan tilføje ønsket funktionalitet efter behov.

Kan gøres fleksibelt med hensyn til datagrundlag og tilføre generisk funktionalitet.

Kræver at man bryder indkapslingen for at kunne stille funktionalitet til rådighed.

Det er kun DataSettet der er tilgængeligt hvis der sendes objekter over en webservice - metoder og attributter frafalder.

Data behandles dybest set stadig som et DataSet, men tilfører ekstra overhead.

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