Net als in mijn vorige verhaal ga ik hier weer een reis door de tijd maken. Deze keer om te kijken hoe onze code door de jaren heen met data om is gegaan. Van de dagen van de eerste PC’s tot en met de nieuwste versie van het .NET framework. Dat wordt een hele reis maar uiteindelijk zullen we toch weer, min of meer, op het beginpunt uitkomen.

Een typisch zakelijke applicatie werkt met gegevens. Gegevens die de gebruiker op invoerschermenen inklopt en die op de een of andere manier opgeslagen worden. De gebruiker hoeft ze de volgende keer dat die het programma gaat gebruiken niet opnieuw in te voeren. Dat klinkt alsof ik een open deur intrap maar in de tijd dat de eerste PC’s het bedrijsleven binnen kwamen waren tools om zulke applicaties te bouwen nog geen vanzelfsprekendheid. Je kon in Turbo Pascal, voorloper van ons geliefde Delphi, heel goed programmeren maar het maken van een invoerscherm was een heidens karwei. En om je gegevens op te kunnen slaan en ook weer binnen afzienbare tijd terug te vinden had je add-ins nodig zoals de database toolbox. In de praktijk maakten we toen applicaties met dBase III en Clipper. Als programmeertaal niet je dat maar het had ingebouwde ondersteuning voor scherm invoer en data opslag.

DIt is een typisch stukje dBase code

USE Relaties INDEX Naam

ZoekPlaats = “Groningen”

@ 2, 0 SAY “Waar ?” GET Plaats PICTURE “!@”

SET FILTER TO Plaats = ZoekPlaats

Rij = 4

GO TOP

DO WHILE !EOF()

    @ Rij, 0 SAY Relaties->Naam

    SKIP

ENDDO

Het fijne van de dBase taal was dat je database velden, zoals Relaties->Naam, en gewone code, zoals ZoekPlaats, door elkaar heen kan gebruiken. Ook het navigeren door de data, met statements zoals SKIP, loopt dwars door je code heen.

dBase en met name Clipper, een dBase compiler met essentiële uitbreidingen op de taal, waren erg productief. Maar de overstap van DOS naar Windows heeft het niet met succes kunnen maken.

Turbo Pascal kreeg uitgebreide ondersteuning voor Windows controls en databases en werd Delphi. Dankzij de Windows controls kwam het maken van een in (of uit) voer scherm binnen bereik en dankzij de database ondersteuning kon je programma zijn gegevens nu ook goed bewaren. Delphi verving al snel Clipper als standaard tool voor het bouwen van applicaties.

Maar er waren enorme verschillen tussen dBase en Delphi. In dBase liepen het schrijven van code en het benaderen van data dwars door elkaar heen. In Delphi werden deze twee gescheiden. Alle operaties op data zaten in database specifieke componenet zoals een tTable en een tQuery. Controls gebruikten deze nooit rechtsreeks maar altijd via een tDatasource component. Niet elke control uit de VCL kon met zulke datasources werken. De control moest expliciete datasource properties hebben om de data vanuit de database naar het scherm en weer terug te krijgen. Het vervelende was dat die controls dan weer niet bruikbaar waren zonder datasource. Met als gevolg dat er een heleboel controls dubbel in de VCL voorkomen, tDBedit is een data-aware textbox en tEdit is niet data aware.

De data zelf is ingepakt in tQuery en tTable componeneten. In code benader je kolommen en parameters via een string die hun naam bevat.

QueryRelaties.Params.ParamByName(‘Plaats’) = ZoekPlaats.Text;

QueryRelaties.Open();

while not QueryRelaties.Eof() do

    begin

    ListBox1.Items.Add(QueryRelaties.FieldByName(‘Naam’).AsString);

    QueryRelaties.Next();

    end;

Deze scheiding tussen data en scherm is goed vanuit het oogpunt van architectuur en past ook goed bij de tijd dat Delphi ontstond; toen was 2-tier de mode. Eén tier met je database en één tier met je front-end. De communicatie tussen deze twee lagen was wel erg intensief. Delphi applicaties werkten met live data. Er was een open connectie met de database, elke update in de frontend ging naar de Database, elke update in de database werd in de front end getoond.

Het .net platform bracht nieuwe inzichten. De scheiding tussen de lagen werd een stuk beter. Een grote stap was het besef dat het najagen van live data een onhaalbare zaak was. In een Delphi applicatie moest je meer en meer je best doen om je data up to date te houden; stel een collega op een andere PC wijzigt data die jij op op je scherm hebt staan. Hoe krijg je die wijzigingen zo snel mogenlijk te zien ? In een WIndows applicatie is dat moeilijk maar theoretisch nog wel te doen. In een webapplicatie is dat onmogelijk; een webpagina heeft per defintie geen verbinding met de (database) server. Het web was van het begin af aan een belangrijke target voor .net. En vanaf het begin af aan was data in .net altijd disconnected. Je voert een query uit op je database en alleen het resultaat gaat naar de client. Als die data wijzigt dan moeten deze data expliciet naar de server worden teruggestuurd om naar de database te worden weggeschrevn.

Een tweede hele fijne verandering was dat alle controls dataaware waren in .Net. Ze hebben niet zoals in Delphi een specifieke property voor de datasource en kolomnaam. In plaats daarvan kon je nu data binden aan verschillende properties van een control. Dat kan aan de tekstinhoud zijn maar ook aan de kleur of het gedrag.

In de eerste versie van het .net framework waren (XML) datasets de manier om met data te werken. Een dataset biedt plaats aan één of meerder tabellen met data, de relaties daartussen en ook eigenschappen zoals het uniek zijn van waardes en kolomgrootte. Een dataset is een complete in memory database die overal aan te binden was. Dat leverde al redelijk duidelijke code op.

TextBox1.Text = relaties.Tables["Relatie"].Rows[0]["Naam"].ToString();

Maar het doet nog wel denken aan FieldByName in Delphi.

Met de wizzards van Visual Studio kan je ook getypeerde  datasets maken, waarin alle tabellen en hun kolommen explicite properties worden. In een getypeerd dataset codeeer je :

TextBox1.Text = relaties2.Relatie[0].Naam;

Dat is een hele vooruitgang.

Maar een XMLdataset heeft ook nog steeds zijn beperkingen. In de eerste plaats heeft een dataset de nodige overhead en trek je een hoop afhankelijkheden naar ado.net je applicatie binnen. Daarnaast is een dataset uitsluitend gericht op data. In een hedendaagse Domain Driven benadering wordt elke entiteit in je applicatie, zoals een Relatie, een class. Een entiteit heeft niet alleen gegevens maar ook gedrag. Gedrag in de vorm van methodes van de class Relatie. Het is lastig om zulk gedrag aan een dataset toe te voegen. Voor een echte goede scheiding tussen data en code zou het fijn zijn om heel gewone Plain Old Clr Objects (POCO’s) te gebruiken voor je  data. Deze poco’s krijg je van je datalaag, gebruik je in je front end en stuur je weer terug naar je datalaag om de wijzigingen op te slaan in de database. Dat is ook de manier waarop een goede OR-mapper zoals nHibernate werkt.

Het goede nieuws is dat je in .net sinds versie 2.0 geen xml datasets meer nodig hebt om aan je componenten te binden. Binden kan nu aan properties van elk object, zolang die maar public zijn.

Deze werkwijze betekent dat je nu met je data kan werken alsof het een willekeurig ander object is. In het volgende voorbeeld heb Ik een repository die relaties leest uit de database. Deze levert een IList van relaties op. Dan kan ik er zo mee om gaan:

Deze code is even wennen, er zit weer lamda expressies in zoals r => r.Plaats == zoekPlaats. Deze zijn we ook al in mijn vorige post tegen gekomen.

In .net 3 kan deze code veel compacter en duidelijker. In de eertse plaats ga ik var’s gebruiken, de compiler kan zelf het type van de variabelen afleiden. Daarnaast gebruikt ik LINQ. Dan ziet het er zo uit

var repo = new RelatieRepository();

var relaties = repo.ListRelaties();

var zoekPlaats = textBox1.Text;

 

var filteredRelaties =

    from relatie in relaties

    orderby Name

    where relatie.Plaats == zoekPlaats

    select relatie;

 

foreach (var relatie in filteredRelaties)

    listBox1.Items.Add(relatie.Name);

LINQ staat voor Language Integrated Natural Query. Het is een heel duidelijk syntax met een select, een from een orderby en een where. Het lijkt een beetje op SQL maar het is gewoon onderdeel van je C# code. En de velden van de data, zoals Name zijn gewoon onderdeel van je code. Achter de schermen wordt het naar de lambda expressies van het eerste voorbeeld vertaald.

Over het wat een hoe van LINQ is veel op het web te vinden. Ook in gedrukte vorm. Een hele duidelijke is de Linq Pocket Reference van O’Reilly. Het was niet voor niets dat 4dotNet juistdeze onlangs aanbood als presentje voor elke ontwikkelaar. Het mooie van LINQ is dat het de data en code weer helemaal bij elkaar brengt.  De gelijkenis met dBase code is geen toeval, het was één van de inspiratiebronnen voor Anders Hejlsberg, maker van Delphi, C# en LINQ.

En wat is nu de moraal van dit verhaal ? Als ontwikkelaar word je doorlopend bestookt met nieuwe technieken. Die zijn meestal mooi en nuttig. Maar gooi je kennis van het oude niet weg, op een dag komt het allemaal weer terug. Niet alleen met data. Zo kijkt menig klassiek ASP ontwikkelaar na al het asp.net geweld met een blik van herkenning naar mvc. En dat is weer een ander verhaal.

 

Stem of voeg toe aanUitleg over het gebruik van deze icons :Voeg dit artikel toe aan Del.icio.us Voeg toe aan je Google bladwijzers Plaats dit bericht op Twitter Geef dit als tip aan je Hyves-vrienden Voeg toe aan je Facebook-profiel Deel met je LinkedIn-contacten Abonneer je op de RSS-feed van deze site Verstuur deze pagina per e-mail via Feedburner Print deze pagina of genereer een PDF-bestand