Min åsikt är att datasets är klumpiga och långsamma och borde förbjudas i all programmering.
En riktigt bra O/R Mapper gör precis det dina datasets gör, bara att du får ett optimerad och framför allt ObjectOrienterad lösning.
Du har ju själv precis insett att ett DataSet
är långsammare än en DataReader, varför då envisas med att använda dem, när du ändå knappast använder alla funktioner som finns i de.De funktioner som du nämner finns inbygda i O/R Mappers som då ger dig samma enkla/enklare hantering av data till/från databasen till/från objekt. Samtidigt som de ger dig en bättre prestanda.Enligt min åsikt så skall ett objekt typ, Customer, innehålla både logik och data. Vilket då gör att en O/R Mapper är att föredra framför användadet av DataSets.
Jag gjorde jämförelser mellan VS.NET inbyggda funktioner och hembyggda databasklasser som jag skrivit gång på gång. men visst kan jag visa vad man kan göra med ett dataset, se nedan.
Det kan jag inte eftersom min O/R Mapper använder sig av DataTable för att hämta data från databasen och fylla mina collections med data.
Då kanske jag kan upplysa dig om att ett dataset är en collection av just Datatables. Och jag frågade dig hur du löser det med en hembyggd databasklass, inte en autogenererad O/R mapper!.
Och om du tittar närmare på det enorma klassbibliotek som genereras av din O/R mappern, vad hittar vi i dem?
jo, vanlig ADO.NET teknik förstås, såsom DataTables,DataRelation,DataRows,DataColumn,DataAdapters, SqlCommand.
Precis vad ett dataset också består av.
Är inte det att kasta stenar i glashus?.
Det löses inte med 2-3 rader kod, må hända att du själv skriver 2-3 rader kod, men det genereras bra mycket mer kod än 2-3 rader.
vad gör då inte en O/R mapper?, skapar ett klassbibliotek åt dig såklart.
skönt att du börjar inse att det inte är fel att använda applikationer som skriver koden åt dej.
Och är du inne på den banan hur mycket kod som genereras kan du också spekulera hur mycket kod som som skapas när du använder en Button klass, det är ganska irrelevant. Det som är relevant är hur mycket kod JAG behöver skriva. Och den inställningenborde varje programmerare ha. Annars kan vi lika gärna gå ner på assemblernivå och programmera, där har du prestanda.
Utöka ditt exempel att du skall börja kontroll den data som du matar in, det kanske är så att om du matar in en stad, så skalldet automatiskt hämta landet där staden ligger i.
På sid.1 gav jag en beskrivning hur man skapar relationer i ett dataset. och där kan du automatiskt hämta hur mycket du vill från andra sammanvävda tabeller.
Sen har jag en fråga till dig, hur skapar du 2 NÄSTLADE DATALIST med 2 sammanvävda tabeller utan att använda Dataset:ets DataRelation objekt.
måste du skapa lösaklasser för att hantera dessa regler, medans jag kan lägga in dessa regler för just den klass som det gäller(typ personnummer kontrol, läggs i classPerson.Tänk sedan att du har 2 olika applikationer som använder sig av samma Person tabell i databasen,då har jag 1 dll som innehåller data och logik för denna tabell. I ditt fall måste du skapa all logik 2 gånger för kontrollera så det blir exakt samma information som hämtas/kontrolleras/lagras. Det är en mardröm för eller senare kommer dessa 2 kodsnuttar att komma ursync. Du måste också skapa och koppla dina datasets 2 gånger.Jag importerar mitt DLL och kan använda min klass enkelt i mina 2 eller flera applikationer. Så för varje applikation som använder sigav ett Person objekt, så ökar du din risk att något blir fel, speciellt om du måste ändra på något så har du många ställen att ändra på.Medans jag har 1 ställe att ändra på och detta slår igenom för alla applikationer.
Vilket dilerium. Jag tror det är dags att jag lär dig lite avancerad DataSet hantering.
När man skapar ett typat dataset i VS.NET skapas en fristående dataset1.cs fil om du tittar i din projektmapp.
Denna .cs är källkoden till det typade dataset:et. Och i denna dataset klass kan man helt ändra om dataset:et från grunden om jag vill det, ändra metoderna, egenskaperna,
lägga till nya egenskaper/metoder införa lite skön logic och kontroll etc.
Men hursomhelst, här lägger jag till raderna SqlDataAdapter.Fill(this.kunder); SqlDataAdapter2.Fill(this.produkter); i konstruktorn för då slipper jag helt dataadapters
eller command objekten när jag använder dataset:et.
Och i OnRowChanged,OnRowDeleted,AddkunderRow eventsen lägger jag kontrollen av indatan på den tabell jag vill kontrollera samt Adapters (eller om jag vill, bara command objekten) för UPDATE/DELETE/INSERT.
och så kompilerar jag den till en .DLL fil.
Alltså, jag har sammansmällt adaptern, logic, dataset:et till en enda klass. Men det är inte nödvändigt att slå ihop allt till 1 enda klass utan man kan göra lite som man vill.
bara ha indata-kontrollen i dataset:et och adaptern för sig om man vill, eller splitta upp datatabellerna, det är upp till en själv. Men jag gillar att ha allt på samma ställe.
Nu har vi ett typat DataSet.DLL som innehåller följande.
1. Alla adaptrars som behövs vid UPDATE,SELECT,DELETE. Och dessa adaptrar anropas automatiskt ifall något förändras i DataSet:et.
2. Alla relationer tabeller sinsemellan finns i dataset:et, och kan användas ifall vi ska använda nästlade datalist:s
3. Alla kolumner i tabellerna har rätt datatyper, (ger compiletimefel istället för runtimefel).
4. All kontroll av indata som läggs in i databasen finns i datatabellernas event.
5. Dataset:et fyller sig själv vid instansiering.
6. Ändrar man dataset:et i runtime ändras databasen samtidigt.
Och hur går det nu till när man använder detta?, jo, enligt följande:
DataSet1 mittdataset;
först instansiera DataSet1 klassen i page_load:
mittdataset=new DataSet1(); //Nu fylls dataset:et automatiskt med tabellerna i databasen istället för att jag måste göra det med "SqlDataAdapter.Fill(mittdataset.kunder);"
DataGrid1.DataSource=mittdataset.kunder; //Bind kunder-tabellen till ett datagrid
DropDownlist1.DataSource=mittdataset.produkter; //Bind produkter-tabellen till en dropdownlist.
Och vill jag tex visa produkterna som varje kund beställt skapar jag bara 2 nästlade datalists och RITAR upp relationen i "View Schema" i VS.NET, (innan jag kompilerar klassen förstås)
DataSource är namnet på datarelationen.
<asp:datalist id="DataList1" runat="server">
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem, "namn") %>
<asp:DataList ID="DataList2" Runat="server" DataSource='<%# DataBinder.Eval(Container.DataItem, "myrelation2") %>'>
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem, "produktnamn") %>
</ItemTemplate>
</asp:DataList>
och slutligen i koden:
DataList1.DataSource=hej;
DataList1.DataBind();
Så letar den själv upp vilka tabeller som hör till vilka.
Och vill jag uppdatera något i databasen ändrar jag bara i dataset:et utan något anrop för att aktivera databasen, eftersom eventet gör det automatiskt som såhär:
mittdataset.kunder[0].namn="olle";
Och för att dra ett exempel om vi har ett editerbart webdatagrid, så det enda jag behöver göra i update händelsen på datagrid:et är detta:
mittdataset.kunder[e.item.itemindex].namn=((TextBox)e.Item.Cells[4].Controls[0]).Text.Trim()
DataGrid1.DataSource=mittdataset.kunder;
DataGrid1.DataBind();
eller om det gäller winforms datagrid lägger jag till följande rad i datagrid:ets händelshanterare för cellerna:
DataGrid1.SetDataBinding(hej.kunder,null); //det är inte mer, bara med denna rad inkluderar jag ALLT som jag skrev i mitt förra inlägg, det som Gladh behövde 15 rader på sig för.
i och med att jag ändrar ett row i en av dataset:ets tabeller så anropas händelsen OnRowChanged automatiskt i dataset:ets tabell där jag la all logic och update-adaptern,
som först kontrollerar så jag inte försöker stoppa in konstiga saker i datatable:t och efter kontroll lägger in det ändrade värdet i databasen. Och samma sak med OnRowDeleted,AddkunderRow, jag behöver inte förklara mer där tror jag.
Asså, förstår ni vad jag menar??, tänk er ett datatable, ändrar ni datatable:t så ändras databasen samtidigt, synkroniserat.
utan att jag behöver anropa någon "update" metod eller liknande. Och dataset klassen kan jag återanvända hur mycket jag vill eftersom det är en Klass. Och nu kommer vi till frågan ni ställer er, vad tungt det måste gå?. Vadå?, hade du splittat
upp dataset:ets commandobjekt/adaptersarna i din kod istället hade det blivit lika mycket. För du använder förmodligen ett command objekt för att exekvera SQL till databasen? . Och du använder förmodligen en adapter för att fylla ditt datatable, och använder du inte en adapter för att fylla ett datatable så görs det manuellt med att dra ur ett SchemaTable ur en datareader och bygga upp datatable:ts DataColumner,DataRows med den,
och efter det fylls datatable:t med .NewRow() metoden på datatable:t, så det är precis samma sak.
Och O/R mappern fyller också datatable:s likadant som en adapter fyller ett datatable i ett dataset.
Enda skillnaden mot ett dataset är att man med O/R mappern kan ta ur varje tabell för sig när man vill jobba med den.
Men det går alldeles utmärkt att göra detta med dataset:et också. Eftersom alla datatable:s i dataset:et är färdiga klasser med "internal" deklarerat, ändra det till "public"
så kan du instansiera ur varje datatableklass för sig:
DataSet1.kunderDataTable kunder=new DataSet1.kunderDataTable();
Så får man en mer objektorienterad filosofi.
Och därmed ökar prestandan eftersom man kan välja vilka tabeller i dataset:et man vill jobba med, så man inte har alla tabeller i minnet samtidigt.