ADO.net : Disconnected klassen

  1. Inleiding
  2. DataTable
  3. DataView
  4. DataSet
  5. DataTableReader

Inleiding

De niet-verbonden datatoegangsklassen worden uitgevoerd binnen de client-toepassing en kunnen gebruikt worden zonder te verbinden met de database. Omdat je een DataTable-object nodig hebt om niet-verbonden klassen te gebruiken beginnen we met een bespreking van deze klasse.

In dit hoofdstuk leren we de niet-verbonden klassen op zich kennen, we zullen dan ook puur met deze klassen werken, en maken nog geen connectie met een database. Op deze manier leer je dat deze klassen ook nuttig kunnen zijn voor intern gegevensbeheer, en ook kunnen gebruikt worden zonder gekoppelde database.

DataTable

Een DataTable representeert gegevens in tabelvorm in het interne geheugen. Deze tabellen bestaan uit kolommen, rijen en beperkingen (constraints).

Een DataTable aanmaken: plaats volgende code in Form1_Load:

DataTable auto = new DataTable("Auto");
Deze code maakt een DataTable waarbij de eigenschap TableName is ingesteld op Auto.

DataColumns aan de tabel toevoegen

Om een tabel te maken, bepalen we het schema van de tabel door kolommen toe te voegen:
// Datakolom toevoegen met alle eigenschappen
DataColumn autoid = new DataColumn("Autoid");
autoid.DataType = typeof(string);
autoid.MaxLength = 10;
autoid.Unique = true;
autoid.AllowDBNull = false;
auto.Columns.Add(autoid);

// Datakolom toevoegen met defaults
DataColumn merk = new DataColumn("Merk");
auto.Columns.Add(merk);

DataColumn bouwjaar = new DataColumn("Bouwjaar");
auto.Columns.Add(bouwjaar);

// Afgeleide kolom met een expressie
DataColumn merkjaar = new DataColumn("MerkJaar");
merkjaar.Expression = "Bouwjaar +' ' +Merk";
auto.Columns.Add(merkjaar);

Voeg nu ook een DataGridView dGVauto toe aan het Formulier

dGVauto.DataSource = auto;

Primaire sleutelkolommen maken

Aangezien een primaire sleutel van een tabel kan bestaan uit meerder kolommen, wordt de eigenschap PrimaryKey ingesteld op een Array van DataColumns.
auto.PrimaryKey = new DataColumn[] { autoid };

DataRows toevoegen aan een tabel

Het DataTable-object bevat een eigenschap Rows, die een DataRow-collectie bevat. Er zijn verschillende manieren om gegevens toe te voegen aan de Rows-collectie:
// nieuwe DataRow toevoegen
DataRow nieuweAuto = auto.NewRow();
nieuweAuto["autoid"] = "1234567";
nieuweAuto["Merk"] = "Ford";
nieuweAuto["bouwjaar"] = 2002;
auto.Rows.Add(nieuweAuto);

// Rij toevoegen via waarden
auto.Rows.Add("54321", "Peugeot", 2000);

// Rij toevoegen met methode LoadDataRow
auto.LoadDataRow(new Object[] { "9567234", "BMW", 2003 }, LoadOption.OverwriteChanges);

Extra info: een DataRow kent verschillende RowStates:

RowState waarde Beschrijving
Detached De DataRow werd aangemaakt maar niet toegevoegd aan een DataTable
Added De DataRow werd aangemaakt en toegevoegd aan een DataTable
Unchanged De DataRow is niet veranderd sinds de laatste aanroep van de methode AcceptChanges. Wanneer de methode AcceptChanges wordt aangeroepen verandert de State van de DataRow in Unchanged.
Modified De DataRow is bewerkt sinds de laatste aanroep van AcceptChanges
Deleted De DataRow is verwijderd met de methode Delete van de DataRow

Extra info: een DataRow wordt in verschillende versies bewaard in het interne geheugen:

DataRowVersion waarde beschrijving
Current De huidige waarde, ook nadat veranderingen zijn aangebracht. Deze versie bestaat steeds, behalve wanneer de rij verwijderd is.
Default Als de DataRowState Added of Modified is, is de Default gelijk aan de Current. Als De DataRowState Deleted is bestaat de Default niet. Als de methode BeginEdit werd uitgevoerd, dan is de versie Proposed.
Original De waarde die origineel in de DataRow werd geladen, of de waarde na de laatste uitvoering van de methode AcceptChanges.
Proposed De waarde wanneer de DataRow bewerkt wordt.

Uitvoer als XML

Je kan een DataTable heel eenvoudig als XML uitvoeren:
auto.WriteXml(@"c:\auto.xml");

Uitvoer:

<?xml version="1.0" standalone="yes"?>
<DocumentElement>
  <Auto>
    <Autoid>1234567</Autoid>
    <Merk>Ford</Merk>
    <Bouwjaar>2002</Bouwjaar>
    <MerkJaar>2002 Ford</MerkJaar>
  </Auto>
  <Auto>
    <Autoid>54321</Autoid>
    <Merk>Peugeot</Merk>
    <Bouwjaar>2000</Bouwjaar>
    <MerkJaar>2000 Peugeot</MerkJaar>
  </Auto>
  <Auto>
    <Autoid>9567234</Autoid>
    <Merk>BMW</Merk>
    <Bouwjaar>2003</Bouwjaar>
    <MerkJaar>2003 BMW</MerkJaar>
  </Auto>
</DocumentElement>
Met een aantal aanpassingen kan je velden als attributen laten uitvoeren, en zelf het databasschema gebruiken (anders worden de veldtypes niet bewaard en is alles een string):
// XML maken
auto.TableName = "Wagen";
auto.Columns["autoid"].ColumnMapping = MappingType.Attribute;
auto.Columns["merk"].ColumnMapping = MappingType.Attribute;
auto.Columns["bouwjaar"].ColumnMapping = MappingType.Attribute;
auto.Columns["merkjaar"].ColumnMapping = MappingType.Hidden;

auto.WriteXml(@"c:\auto.xml", XmlWriteMode.WriteSchema);

Uitvoer:

<?xml version="1.0" standalone="yes"?>
<NewDataSet>
  <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="Wagen" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="Wagen">
            <xs:complexType>
              <xs:attribute name="Autoid" use="required">
                <xs:simpleType>
                  <xs:restriction base="xs:string">
                    <xs:maxLength value="10" />
                  </xs:restriction>
                </xs:simpleType>
              </xs:attribute>
              <xs:attribute name="Merk" type="xs:string" />
              <xs:attribute name="Bouwjaar" type="xs:string" />
              <xs:attribute name="MerkJaar" msdata:ReadOnly="true" msdata:Expression="Bouwjaar +' ' +Merk" type="xs:string" use="prohibited" />
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
      <xs:unique name="Constraint1" msdata:PrimaryKey="true">
        <xs:selector xpath=".//Wagen" />
        <xs:field xpath="@Autoid" />
      </xs:unique>
    </xs:element>
  </xs:schema>
  <Wagen Autoid="1234567" Merk="Ford" Bouwjaar="2002" />
  <Wagen Autoid="54321" Merk="Peugeot" Bouwjaar="2000" />
  <Wagen Autoid="9567234" Merk="BMW" Bouwjaar="2003" />
</NewDataSet>

DataView

Het object DataView levert je een venster op een DataTable.
De DataView kan gesorteerd en gefilterd worden.

Sorteren met een DataView

Om de gegevens uit een DataTable te sorteren kan je gebruik maken van een DataView:

DataView vauto = new DataView(auto);
vauto.Sort = "Merk desc, Bouwjaar desc";
We stellen de DataSource van de DataGridView in op de DataView i.p.v. de DataTable:
dGVauto.DataSource = vauto;

Merk op dat de Ford hier vervangen werd door een BMW, rijdt wat sneller :)

Filteren met een DataView

DataView vauto = new DataView(auto);
vauto.RowFilter = "Merk like 'B%' and Bouwjaar > 2002";

Met de RowStateFilter kan je records filteren op basis van de RowState.

DataSet

DataSet, DataTable en DataRelation

De DataSet is een relationele representatie van gegevens in het geheugen van de computer en is het primaire object bij het werken met disconnected data. De DataSet bevat een collectie van DataTable en DataRelation objecten. De DataSet kan unieke en foreign key constraints bevatten om dataintegriteit af te dwingen.

Voeg een nieuw formulier Form2 toe aan het project disconnected

In Program.cs zorg je ervoor dat dit nieuwe formulier getoond wordt

Code voor Form2_Load:

DataSet verkoop = new DataSet("Verkoop");

DataTable verkoper = verkoop.Tables.Add("Verkoper");
verkoper.Columns.Add("Id",typeof(Guid));
verkoper.Columns.Add("Naam",typeof(string));
verkoper.Columns.Add("Straat",typeof(string));
verkoper.Columns.Add("Nr",typeof(string));
verkoper.Columns.Add("Postcode",typeof(string));
verkoper.Columns.Add("Woonplaats",typeof(string));
verkoper.Columns.Add("Land",typeof(string));
verkoper.PrimaryKey = new DataColumn[] { verkoper.Columns["Id"] };


DataTable artikel = verkoop.Tables.Add("Artikel");
artikel.Columns.Add("Id",typeof(Guid));
artikel.Columns.Add("VerkoperId",typeof(Guid));
artikel.Columns.Add("code",typeof(string));
artikel.Columns.Add("Beschrijving",typeof(string));
artikel.Columns.Add("Aankoopprijs",typeof(decimal));
artikel.Columns.Add("Verkoopprijs",typeof(decimal));
artikel.PrimaryKey = new DataColumn[] { artikel.Columns["Id"] };

verkoop.Relations.Add("verkoper_artikel", verkoper.Columns["Id"], artikel.Columns["Verkoperid"]);

We tonen de twee tabellen inhoudsloos op het scherm:
Voeg twee DataGridViews toe aan Form2: dGVverkoper en dGVartikel

dGVverkoper.DataSource = verkoop.Tables["verkoper"];
dGVartikel.DataSource = verkoop.Tables["artikel"];

XSD-bestanden en Visual Studio 2008

We hebben een DataSet gemaakt met twee tabellen: verkoper en artikel en een relatie tussen de twee tabellen.

De code om de tabel verkoper aan te spreken is als volgt:

DataTable verkopertabel = verkoop.Tables["Verkoper"];
Als je de tabelnaam verkeerd spelt zal Visual Studio je fout niet aangeven, de fout zal slechts runtime je programma doen vastlopen.

Om deze reden is het beter een gespecialiseerde klasse te maken voor je DataSet die overerft van de klasse DataSet. Deze gespecialiseerde klasse kan dan een eigenschap Verkoper bevatten die als volgt benaderd kan worden:

DataTable verkopertabel = verkoop.Verkoper;

Je kan deze subklasse zelf schrijven, maar het is gewoonlijk beter om een XML schema definition (XSD)-bestand te voorzien en de afgeleide klasse door Visual Studio te laten maken. Visual Studio beschikt zelfs over een DataSet Editor waarmee je op een gebruiksvriendelijke, grafische manier een XSD-bestand kan aanmaken.

Voeg een DataSet-bestand aan je project toe: VerkoopSchema.xsd

Maak de tabellen Verkoper en Artikel aan met de DataSet Editor (rechtklikken, add...)

Maak een relatie tussen de tabellen:
Parenttabel: Verkoper(Id) / Childtable: Artikel (VerkoperId)

Foreign key constraints (cascade update, delete, geen child indien geen parent,...) kan je ook met de DataSet Editor maken.

Voeg een derde formulier Form3 toe.
Voeg twee DataGridViews toe aan Form3: dGVverkoper en dGVartikel

Voeg een DataSet toe aan Form3 (Toolbox, onderdeel Data):
Typed DataSet disconnected.VerkoopSchema, geef als Name dsVerkoop

Voorzie in Form3_Load:

dGVverkoper.DataSource = dsVerkoop.Verkoper;
dGVartikel.DataSource = dsVerkoop.Artikel;

Je kan wat gegevens voorzien in de tabellen:

DataTable v = dsVerkoop.Verkoper;
DataRow verkoper = v.NewRow();
Guid verkoperid = Guid.NewGuid();
verkoper["Id"] = verkoperid;
verkoper["Naam"] = "Ivowinkel";

v.Rows.Add(verkoper);

DataTable a = dsVerkoop.Artikel;

DataRow artikel = a.NewRow();
artikel["Id"] = Guid.NewGuid();
artikel["VerkoperId"] = verkoperid;
artikel["code"] = "AAA";
artikel["beschrijving"] = "Artikel A";
artikel["aankoopprijs"] = 10.0;
artikel["verkoopprijs"] = 15.0;

a.Rows.Add(artikel);

artikel = a.NewRow();
artikel["Id"] = Guid.NewGuid();
artikel["VerkoperId"] = verkoperid;
artikel["code"] = "BBB";
artikel["beschrijving"] = "Artikel B";
artikel["aankoopprijs"] = 20.0;
artikel["verkoopprijs"] = 26.0;

a.Rows.Add(artikel);

dGVverkoper.DataSource = dsVerkoop.Verkoper;
dGVartikel.DataSource = dsVerkoop.Artikel;

DataSet omzetten naar XML

Je kan een gevulde dataset eenvoudig omzetten in XML:
dsVerkoop.WriteXml(@"c:\verkoop.xml", XmlWriteMode.IgnoreSchema);

Resultaat:

<?xml version="1.0" standalone="yes"?>
<VerkoopSchema xmlns="http://tempuri.org/VerkoopSchema.xsd">
  <Verkoper>
    <Id>32cf9d4e-841f-421a-bbc5-c2bc0eb3715b</Id>
    <Naam>Ivowinkel</Naam>
  </Verkoper>
  <Artikel>
    <Id>9a1da7d2-9d98-4c1e-843a-5cfeaca950ed</Id>
    <VerkoperId>32cf9d4e-841f-421a-bbc5-c2bc0eb3715b</VerkoperId>
    <Code>AAA</Code>
    <Beschrijving>Artikel A</Beschrijving>
    <Aankoopprijs>10</Aankoopprijs>
    <Verkoopprijs>15</Verkoopprijs>
  </Artikel>
  <Artikel>
    <Id>79a10d2e-2642-455e-875f-3fc8fc0aa98f</Id>
    <VerkoperId>32cf9d4e-841f-421a-bbc5-c2bc0eb3715b</VerkoperId>
    <Code>BBB</Code>
    <Beschrijving>Artikel B</Beschrijving>
    <Aankoopprijs>20</Aankoopprijs>
    <Verkoopprijs>26</Verkoopprijs>
  </Artikel>
</VerkoopSchema>

DataTableReader

Een DataTableReader (nieuw in .NET 2.0) laat je lussen doorheen DataRow-objecten in een DataTable. De DataTableReader is forward-only, read-only en kan gebruikt worden om rijen van een tabel op te vragen zonder een lus te schrijven.

Een DataSet retourneert met de methode CreateDataReader een DataTableReader. Bevat de DataSet meerdere tabellen, dan kan je naar de volgende tabel overgaan met de methode NextResult.

In het volgende voorbeeld geven we de namen van de verkopers en de beschrijvingen van de artikels weer in een ListBox lbArtikel.

DataTableReader dtr = dsVerkoop.CreateDataReader();
while (dtr.Read())
{
    lbArtikel.Items.Add(dtr["naam"]);
}
dtr.NextResult();
while (dtr.Read())
{
    lbArtikel.Items.Add(dtr["beschrijving"]);
}

Meer tutorials:
leer ook: html | xhtml | css | asp | asp.net | c# | ado.net | linq | ajax | java | javascript
Valid HTML 4.01! Valid CSS! © - Cursusweb