webForumDet fria alternativet

Bygga en egen dbklass

.NET

118 svar · 5 017 visningar · startad av Swordfishy · sida 5 av 6

Frågan, av Swordfishy

Goddagens, Tidigare har jag sysslat en del med klassiska ASP tillsammans med mySQL. Nu är det dock dags att övergå till ASP.NET med mySQL. Jag står inför ett hinder, funderar på att bygga en serverkontroll (kompilerad kod till .dll) som sköter arbetet (anslutning, hämtar data, uppdaterar, ta bort data osv..) mot min mySQL databas. Tror det kan kallas DAL? Min tanke är att en sådan här lösning:

Läs frågan i sin helhet →
Medlem sedan nov. 2003569 inlägg
#81

DAL hämtar DataTable, DataReader, DataSet, vad man nu vill och ger den till mappern som skapar ett starkt typat objekt.

Det har absolut ingen betydelse vilket objekt som fyller. Saken är den att det måste göras innan du får tillgång till datat.

starkt typade object behöver jag inte veta vad databaskolumnerna heter, objektet har sina attribut istället. Kanske fattade ditt inlägg fel.

Ja du fattar fel. du ser att det står:
dataset.kunder[12].namn

kunder är vad din tabell i databasen heter, 12 är vilken rad i DataTablet(motsvarar raderna i databastabellen), namn är vilken kolumn i tabellen. Detta ordnar intellisensen åt dej. jag behöver heller inte veta vad alla kolumner och tabeller heter.

När jag har en collection av mina objekt kan jag databinda rakt av mot t.ex ett DataGrid. Jag behöver bara plocka ut objektets attribut i griddets ItemTemplate.

Det finns ett lättare sätt, och det heter DataSet, såhär binder jag till ett DataGrid:
DataGrid1.DataSource=dataset.kunder;
DataGrid1.DataBind();
Varför använder du en ItemTemplate när DataGrid:et kan skapa kolumnerna automatiskt med hjälp av DataTablet:s kolumn-schema?.

då det som tar tid är inte skapandet av DataTable/DataSet/Object/Collection av objent.
Utan Databasanropet och transport av data från databaservern till din applicationsserver.
Vi pratar millisekunder och sekunder i detta skede, medans vi pratar mikrosekunder för att skapa och fylla ett objekt.

Om du tex ska ta ut 100 värden ur databasen så måste:

O/R:
Först måste 100 DataRows i DataTable:t skapas och fyllas.
Och efter det måste 100 ytterligare Object i din Collection skapas.
Och sen typkonverteras alla dessa 100 värden innan de läggs in i din Collection, för att annars blir det inte starkt typat.

DataSet:
Först måste 100 DataRows i DataTable:t skapas och fyllas.
Sen typcastas alla dessa värden 100 gånger när man plockar ut värdena till sitt program.

Håller du med?.

Datan i typade datasets ligger i DataTablen och alltså behövs minst 3 operationer för att få ut rätt data och oftas inkluderas en
TypCastning från ett objekt till en ValueType (så kallad boxing/unboxing) och detta är prestandkrävande.
Problemet med ett typat dataset är att detta sker varje gång som man vill hämta ut data. Så vill du hämta ut
Namnet på en kund 4 gånger så görs det alltså 3*4 operationer.
Medans för ett objekt som är fyllt från en O/R Mapper så görs detta endast när objektet fylls med data alltså 1 gång.

Hämtar du 100 värden med din O/R skapar den 100 DataRows + 100 nya Object(till din collection) + 100 typkastningar vid införandet i Collection.
Om man jämför med DataSet: skapa 100 DataRows + 100 typcastningar vid utplockandet av värdena i mitt program.
Skillnaden är bara var typcastningen görs, i O/R fallet: innan den läggs in i Collection, DataSet efter införandet i DataTable.
Men O/R måste också skapa 100 nya object till din collection och fylla dem, vilket inte DataSet:et behöver.
Jag kan inte se prestanda förlusten med dataset.

Medlem sedan apr. 2004778 inlägg
#82

Hur länge har ni hållit på? Vad har ni gjort? Vad har ni gått för väg?

Ja, jag ska väl svara på min egen fråga också.

Utbildningen blev 3,5 år Computer Science i Californien 94-98. Grunderna lärdes ut i Pascal och C, sen har det t.ex. varit datastrukturer i Pascal, objekt-orientering i C++ och Java och databasdesign.
Har jobbat med webbutveckling sedan februari 98. Började med ASP då och är självlärd. Fram till juli 2001 jobbade jag som webbutvecklare, systemarkitekt och it-ansvarig på två reklambyråer och ett konsultföretag i Stockholm. Efter det har jag drivit eget företag.
.NET började jag peta i från Beta 2 av .NET Framework. Satt med notepad och commandline innan jag började med Visual Studio.

Jon:

mmm. Jag blir direkt lite skeptiskt. Men men. Man får väl vara öppen för nya lösningar. Jag har gärna 4-5 lager när jag ska designa lösningar men jag kanske är lite extrem i vissa fall. Beror väl på att jag har varit inblandad i bygget av ett riktigt stort system i VB för ett par år seddan som inte hade någon egentlig lagerstruktur. Det var en mardröm att underhålla koden som ni säkert förstår.

Ja, jag håller med dig. Jag är också lite skeptiskt. Dels för att även jag bygger mina olika lager, ibland upp till 7 stycken tror jag. Extrem?
Dels för att jag har mycket databasdesign bakom mig och inbillar mig att man kan vinna mycket prestanda genom att ha en välstrukturerad databas med specificerade procedurer som inte returnerar en massa onödig data.
Det är också en av anledningarna till att jag inte använder en O/R mapper. Jag vill ofta ställa komplicerade sql-frågor eftersom ju större resultat en sp returnerar, desto mer resurser krävs.
Visst, då finns möjligheten att använda dynamiska sql-frågor i O/R mappern men jag vill även gärna inbilla mig att en stored procedure är snabbare.
Däremot när det gäller Yukon och ObjectSpaces så får man nog ha ett öppet sinne. Flerskiktslösningen kommer fortfarande att finnas där men det kanske blir lättare att bygga den på det sätt man själv gör det idag utan att kompromissa så mycket.
Det är ju något man måste prova på i alla fall när det väl kommer.

Nöff:

Det finns ett lättare sätt, och det heter DataSet, såhär binder jag till ett DataGrid:
DataGrid1.DataSource=dataset.kunder;
DataGrid1.DataBind();
Varför använder du en ItemTemplate när DataGrid:et kan skapa kolumnerna automatiskt med hjälp av DataTablet:s kolumn-schema?.

Jag använder TemplateColumns i mina DataGrids de gånger jag behöver bearbeta en kolumn i DataBound. I övrigt så använder jag BoundColumn. Jag vet mycket väl vad man kan göra med de inbyggda ASP.NET kontrollerna, vad som kan göras automatiskt och vad man själv kan påverka för att maximera resultatet.

Så här binder jag till ett DataGrid, Repeater, DataList eller vad det nu blir:

dgrStat.DataSource = statCol
dgrStat.DataBind()

statCol är min collection av objekt.
Som Jon säger, i stora prjojekt kan det vara en mardröm att inte ha en ordentlig lagerstruktur.

Jag är nyfiken på ett par saker Nöff. Hur stora projekt har du använt din lösning på? Vad är din bakgrund?

Medlem sedan maj 20012 812 inlägg
#83

Hämtar du 100 värden med din O/R skapar den 100 DataRows + 100 nya Object(till din collection) + 100 typkastningar vid införandet i Collection.
Om man jämför med DataSet: skapa 100 DataRows + 100 typcastningar vid utplockandet av värdena i mitt program.
Skillnaden är bara var typcastningen görs, i O/R fallet: innan den läggs in i Collection, DataSet efter införandet i DataTable.
Men O/R måste också skapa 100 nya object till din collection och fylla dem, vilket inte DataSet:et behöver.
Jag kan inte se prestanda förlusten med dataset.

Nej om man tittar på det som du skriver här så ser man ingen prestand förlust med dataseten, men världen är inte så enkel.

Om jag har 1 eller 100 rader i en databas så får jag 1 eller 100 objekt från min O/R Mapper. Om jag i min rad har 2 columner, typ Namn och Ålder så har jag 2 variabler i mitt objekt som skall typomvandlas till rätt sort.

Följande sker då.
- Jag har min DataRad, i denna datarad så fram första kolumnen med hjälp av variables namn, typ DataRow["Namn"] och får tillbaka ett objekt, denna castar jag sedan till en sträng. Likadant för åldern. Jag har nu gjort 2 typcastningar för att fylla mitt objekt med data.

Om jag nu skriver ut detta objekt 100 gånger på sidan så har jag bara gjort 2 typcastningar.

Med datasetet så har du inga typcastningar när du börjar jobba med, så för kolumnen Namn och Ålder har du inte gjort någonting.

När du sedan skall hämta ut namnet så måste du gå in i din datatable och hämta ut rätt datarad (detta motsvarar att jag hämtar ett objekt från en collection), sedan skall du hämta ut rätt kolumn från denna datarad, motsvars av DataRow["Namn"], och sedan typcastat denna till en sträng. Och likadant för ålder.
Så för att hämta ut ett värde ur ditt dataset så gör du 2 typcastningar.

Om du nu skriver ut din dataRows Namn och Ålder hundra gånger så kommer du göra 2 typcastningar för varje gång, alltså total 200 typcastning, nu tog jag bar med typcastningarna men det sker ju fler saker som händre varje gång, typ att hitta rätt kolumn i dataraden, detta görs endast 1 gång i en O/R Mapper, men VARJE gång med ett dataset.

Så det tar längre tid att skapa ett (eller flera) objekt med en O/R Mapper, medans det tar längre tid när du använder dina datasets jämfört med ett objekt. Och som jag nämde tidigare så är det inte skapandet av objekt och collections som tar tid, utan det som tar tid är att hämta data från databasen, så fast att jag skapar en massa objekt och typcastar informationen i databasen till rätt variable i objektet så kommer den tiden det tar att göra det vara så försumbar jämfört med tiden det tar för DAL:et att hämta data från databasen så det kommer inte märkas någon större skillnad jämfört med att använda DataSet.

Om vi säger att det tar 10 sekunder att hämta ut data från databasen och fylla en collections med data med en O/R Mapper, så kommer 9 av dessa sekunder att vara att hämta information till en datatabel, och 1 sekund att göra om alla data till ett objekt. Typcastningen och skapandet av data.

Det betyder att det tar 9 sekunder för dig att fylla DataSetet.

Vi har nu samma data att jobba med, du i ett dataset och jag i ett objekt.

Om det tog 1 sekund att skapa objektet så var det typcastningen som tog 0.5 sekunder. Det betyder att varje gång som du hämtar data från ditt dataset så tar det 0.5 sekunder att omvandla datan i dataRown till ett objekt som skickas tillbaka.

Så om jag skriver ut mitt objekt 100 gånger, så behöver jag inte lägga någon tid på typcastning, medans om du vill skriva ut samma sak med DataSetet 100 gångern kommer att få lägga 100 *0.5 = 50 sekunder på att skriva ut samma sak.

Där har du prestandaskillnaden!!!

Om du sedan tittar i din typade datasetsklass, så har den en massa annan information som man kan tillgå, all denna information måste också skapas när man hämtar datan från databasen och skapar ditt typade dataset. Denna extra information slipper jag eftersom jag inte har den i mina objekt.

Det finns ett lättare sätt, och det heter DataSet, såhär binder jag till ett DataGrid:
DataGrid1.DataSource=dataset.kunder;
DataGrid1.DataBind();

Angående bindningen till DataSource, så vill det ju bara till att objektet implementer IEnumerable (eller var det IEnumeration) så kan man binda vad som helst till en datagrid.DataSource.

Fast vem använder en DataGrid frivilligt, den har ungefär samma användnings område som DataSetet, yttersbegränsad, och det är om jag vill skapa mig en acces kopia på nätet. Det finns snabbare alternativ och det är givetviss Repeatern som fylls med en DataReader, det är optimal ur prestandsynpunkt, och så ingen <% DataBinder %> för att binda data, utan in med databindningen i event OnItemDataBound.

- M

När jag sedan använder mig av mitt

Medlem sedan maj 20012 812 inlägg
#84

Det är också en av anledningarna till att jag inte använder en O/R mapper. Jag vill ofta ställa komplicerade sql-frågor eftersom ju större resultat en sp returnerar, desto mer resurser krävs.
Visst, då finns möjligheten att använda dynamiska sql-frågor i O/R mappern men jag vill även gärna inbilla mig att en stored procedure är snabbare.

Min O/R Mapper kan använda både SP eller SQL. Antingen kan jag skicka in att jag vill exekvera en SP, eller så kan O/R Mappern skapas SQL dynamiskt. Fördelen är att jag slipper skriva en massa enkla SP's för att hämta ut by ID eller en delmängd, men kan skapa avancerade SP's om jag vill ha flera inner joins och annat trams.

I och med SQL Server 2000 så är faktiskt inte en SP snabbare än dynamisk SQL. Första gången frågan körs, JA. Men sedan så cachas exekveringsplanen för just den SQL frågan för just den tabellen, detta kräver dock att man skriver fullständig sökväg till tabellen, och inte bara tabellens namn. Så andra gången man kör samma SQL så tar det lika långtid som för SP:n.

Själv så använder jag alltid ItemTemplat och eventet OnItemBound så fort jag skall binda data till en DataGrid/Repeater/list. Detta för att slippa den late-binding som sker med hjälp av <% DataBinder() %> kommandot. DataBound brukar jag aldrig använda, men antar att den fungera utan reflextions och latebinding.

- Magnus

Medlem sedan mars 20023 561 inlägg
#85

Gladh, du förklarar väldigt utförligt i teorin, men hur ser det ut praktiskt. Som det redan efterfrågats i denna tråd på hur en O/R Mapper i själva verket ser ut, skulle även jag gärna se det... ;)

Även hur du enbart använder eventet OnItemBound, istället för DataBinder()-kommandot.

Medlem sedan okt. 2002188 inlägg
#86

Gladh skrev:

de flesta or-mappers använder sig nog av reflections..

Man måste (väl) använda sig av reflections för att fylla sitt objekt med data. Annars får man göra lösningen som finns i typade datasets, alltså lägga datan i en HashTable och sedan hämta ut den efterhand.

Jag har då inte hittat något sätt att fylla en variabel i ett objekt dynamiskt utan att använda mig av GetType() och SetValue(). Om du vet något annat sätt är jag riktigt intresserad.

Själv har jag Attribute på alla variabler som skall fyllas med data, dessa hämtas ut med hjälp av reflections, men cachas sedan, så att om man fyller en collections med data, så behöver man endast hämta ut attributen en gång.

- M

Hej

Har inte tillgång till koden här så kan inte visa exakt hur det ser ut. Men i sisyphus, så anger man vad som skall lagras var med attribut, dessa läses in första gången man använder ett objekt av en viss typ och lagras sedan in en hashtable, tror jag. Då man sen vill ha ett objekt så går man igenom denna hashtable och använder sig av setValue för att lista ut vart de olika värdena skall sättas. Men jag har ändrat denna funktion så att om du anropar denna så skickas objektet som du skall fylla vidare till en annan klass. Denna klass kollar om det finns en mapperklass för denna klassen och finns det en sådan så skickas objektet vidare till den. Mapperklassen konveterar objektet till rätt typ och sätter sen alla properties. Så istället för setValue så blir det ex. item.Name = reader(2); Om det inte finns en mapperklass för detta objekt och om vi kör i debugläge så skrivs en xmlfil med data om hur klassen skall mappas, mha av attributen som lagrats innan. Denna xmlfil likar ojbs mappningsfil.

När sen projektet är klart eller börjar bli klart så tar jag dessa xmlfiler och utifrån dem så skapar jag alla mappningsklasser för alla objekten och en factory för dessa( den klassen som anropas från metoden) och när jag sen kör skarpt och har alla mappningsfiler så slipper jag använda mig av reflection för att sätta värden. Lägger jag till en ny fil och inte lägger till en mappningsklass så kommer den att använda sig av reflections.

Men summa summarum så.. man kommer inte ifrån reflections alltid, men genom detta så kan jag minska ner användandet av reflections till ett minimum. Funderar på att göra samma sak då man skapar objekt, men har för mig jag sprang på någon bugg där..

Medlem sedan nov. 2003569 inlägg
#87

Om jag nu skriver ut detta objekt 100 gånger på sidan så har jag bara gjort 2 typcastningar.
Om du nu skriver ut din dataRows Namn och Ålder hundra gånger

Gladh!, man skriver aldrig ut exakt samma värde på skärmen 100 gånger.
Du tar ett exempel där man ska skriva ut namnet "jakob" 100 gånger på skärmen från exakt samma objekt. Den jämförelsen passar bäst i papperskorgen!. Jag vet att du försöker vrida och vända på saker och
hitta jämförelser som är till din fördel, men detta var ett bottennapp om inte rentav en kuggfråga
för att se om jag gick på det eller ej.
Saken är den att det sker exakt lika många typcastningar mellan O/R(före) och dataset(efter),
skillnaden mellan ditt och mitt är att O/R mappern också! måste skapa 100 ytterligare objekt i minnet
och dessutom fylla dem med exakt samma information som det DataTable den skapar allt ifrån.
Detta gör O/R mappern oerhört prestanda krävande.

Jag vill lägga ner nu, det är fint väder, och lördag!!!!

Medlem sedan dec. 20003 887 inlägg
#88

Men sluta tjata... :OO

Läs detta så får du veta att du har både rätt och fel.

Medlem sedan apr. 2004778 inlägg
#89

Som jag ser det så är den slutgiltiga skillnaden att den ena sättet att arbeta kan man använda till endast små projekt och den andra fungerar i både små och stora projekt.

Så, mitt sista inlägg i den här diskussionen.

Vi kanske ses i nåt annat inlägg.

Medlem sedan jan. 20012 204 inlägg
#90

Josef skrev:

Gladh, du förklarar väldigt utförligt i teorin, men hur ser det ut praktiskt. Som det redan efterfrågats i denna tråd på hur en O/R Mapper i själva verket ser ut, skulle även jag gärna se det... ;)

Gladh har säkert suttit uppe flera sena nätter i flera veckor och utvecklat sin O/R mapper, tror aldig han släpper källkoden till fler personer än NETWork ;)

Medlem sedan feb. 20013 023 inlägg
#91

Intressant diskussion. Det verkar vara många som inte fattat att Nöffs ego är ungefär 300 ggr större än hans kunskaper.

Han har inte jobbat i några stora projekt och förstår inte hur man arbetar i sådana.

Jag kan inte så mycket om .NET själv, men det är jag medveten om och kan därför lära mig av andra. Vissa saknar ibland förmåga att inse sina egna brister...

http://www.webforum.nu/showthread.php?s=&forumid=29&threadid=96910

Medlem sedan mars 20023 561 inlägg
#92

P skrev:

Gladh har säkert suttit uppe flera sena nätter i flera veckor och utvecklat sin O/R mapper, tror aldig han släpper källkoden till fler personer än NETWork ;)

Jag menar inte att han ska ge mig hela sin O/R Mapper, bara ge mig en liten hint om hur man ska tänka och bygga upp den... ;)

Medlem sedan juli 20011 304 inlägg
#93

Klart att vi (i alla fall jag) ska hjälpa dig så gott vi kan Josef!
Jag föreslår att du startar en ny tråd eller tar upp en gammal där vi har diskuterat saken lite förut. Den här tråden kommer jag inte att fortsätta läsa av naturliga skäl :)

Medlem sedan mars 20023 561 inlägg
#94

Jon skrev:

Klart att vi (i alla fall jag) ska hjälpa dig så gott vi kan Josef!
Jag föreslår att du startar en ny tråd eller tar upp en gammal där vi har diskuterat saken lite förut. Den här tråden kommer jag inte att fortsätta läsa av naturliga skäl :)

Tackar för det! :bire

Medlem sedan apr. 2004778 inlägg
#95

Josef, jag kan rekommendera att lägga ut $50 (ca390 spänn) på en prenumeration hos Paul Wilson, https://www.wilsondotnet.com
Du får alla hans kontroller inklusive source-kod. Du får till och med koden till hans ORMapper. Värt varenda öre.
Väldigt bra sätt att lära sig genom att stega igenom kod rad för rad och se vad som verkligen händer.

Medlem sedan maj 20012 812 inlägg
#96

Gladh!, man skriver aldrig ut exakt samma värde på skärmen 100 gånger.
Du tar ett exempel där man ska skriva ut namnet "jakob" 100 gånger på skärmen från exakt samma objekt. Den jämförelsen passar bäst i papperskorgen!.

Nöff! Jag kan inte förklara det för dig på något annat sätt. Givetvis så skriver man aldrig ut samma objekt 100 gånger på en skärm det vara bara för att förtydliga det som händer. Lika lite som att det tar 10 sekunder att hämta data från databasen.

Väldigt sällan så använder man sina objekt endast 1 gång. Om man bara vill presentera datan rakt upp och ner på en websida, så använder man givetvis inte en O/R Mapper, det är inte det den är tillför.

Man använder den när man vill kunna jobba med sina objekt. Ett typiskt användande är om man har en applikation som presenterar kontouppgifter från en bank.

Först så presenterar uppgifterna från banken. Sedan så vill du ta ut 200 kronor, då kontrolleras det i din total att du har mer än 200 kronor på kontot, sedan så dras det 200 kronor från konto.

Här har du nu en applikation som har använt ett objekts variabel, 3 gånger. Till denna sker endast 1 typcastning, medans ditt DataSet kräver 3. Om jag sedan vill ta ut ytterligare 200 kronor, så sker det ytterligare 3 typcastning för dig, men ingen via en O/R Mapper.

- Magnus

Medlem sedan maj 20012 812 inlägg
#97

Jag menar inte att han ska ge mig hela sin O/R Mapper, bara ge mig en liten hint om hur man ska tänka och bygga upp den

Det har jag redan gjort i något inlägg här. Sök efter det, där finns en väldigt förenklad version som visar hur man kan göra.

- M

Medlem sedan apr. 2004778 inlägg
#98

Gladh, det är lika bra att du ger upp. Han vill inte förstå något annat än det sätt han själv jobbar på.

Medlem sedan maj 20012 812 inlägg
#99

Mapperklassen konveterar objektet till rätt typ och sätter sen alla properties. Så istället för setValue så blir det ex. item.Name = reader(2);

Walker, jag gör som din första beskrivning, har attribut på alla variabler, och läser in dessa i en cache. Och med SetValue så sätter jag datan.

Däremot så blir jag riktigt intresserad av ovanstående: item.name = reader(2);
Jag har letat efternågot sånt. Att matcha ihop reader(2) och name är ingen konst, det är att göra en dynamisk: item.name som blir svår. Eller är detta något som skapas för varje klass, så om du har 2 klasser så får du 2 stycken funktioner, alltså en funktion som fyller klass1 och en som fyller klass2 och dessa funktioner skapas som kod utifrån klasserna. Alltså lite som en codegen.

Har du en länk till sisyphus så man kan se hur de har gjort?

- magnus

Medlem sedan apr. 2004778 inlägg
271 ms totalt · 4 externa anrop · v20260731065814-full.a51de22e
121 ms — deklarationer (db)
0 ms — hämta statistik (cache)
145 ms — hämta tråd, inlägg och bilagor (db)
124 ms — ändringar (db)