Linq: leuk maar link

 
28 november 2009

Zoals de titel al suggereert: ik vind Linq leuk op een maar na.

Laat ik eerst eens wat punten opnoemen die ik leuk en goed vind van Linq:

  • Het ziet er bekend uit
  • Type-Safe queries
  • Bruikbaar over meerdere bronnen
  • Uitbreidbaar


Laat mij deze punten eerst maar eens verduidelijken.

Linq ziet er bekend uit omdat het taaltje lijkt op SQL in een iets andere volgorde. Dus mensen zullen het snel begrijpen. Dat betekent ook dat mensen snel up-to-speed zijn om te helpen bij je project en dat is wel een pluspunt.

Omdat een compiler over je Linq queries gaat is het type-safe en dat is mooi. Geen gezeur meer met SQL tikken in een StringBuilder en deze dan uitvoeren om er tijdens het uitvoeren van je programma tegen een exceptie aan te lopen omdat je query niet goed was.

Linq werkt over meerdere bronnen. De meest voor de hand liggende is uiteraard Linq to SQL. Dit geeft je de mogelijkheid om Linq te gebruiken over je database. Uiteraard moet er dan wel een provider voor zijn die het ondersteund. Er zit in het Microsoft .NET Framework 3.5 ook een Linq to XML provider. Dit betekent niet meer stoeien met nodes maar gewoon je XPath query uitvoeren via Linq. Uiteraard is het collection framework van .NET ook uitgebreid met Linq mogelijkheden; dit heet Linq to Objects. Zo zullen er nog wel wat onderdelen in het framework zitten die ook Linq ondersteunen. Zelf ben ik alleen met deze onderdelen in aanraking gekomen.

Het is zelfs mogelijk om je eigen Linq provider te schrijven. Dit doe je door (onder andere) IQueryable te implementeren.

Het probleem
Als ontwikkelaar vind ik persoonlijk code completion een geweldig iets. Dit zorgt er voor dat je niet alle methoden en eigenschappen van elke Class uit je hoofd hoeft te kennen.
Nu is het probleem dat een Linq enabled object in samenwerking met code completion eigenlijk tegen je liegt.

Klein voorbeeld
Dit voorbeeld werkt (op ontbrekende onderdelen na).

var personen = from psn in contextPersonen
                     where psn.NAAM.Contains(strNaam)
                     select psn;
return personen.Take(100);

Deze code zorgt er voor dat 100 personen waar ‘strNaam’ voorkomt in de naam worden geretourneerd. Of niet?

Analyse
Zodra we deze code tikken en een punt achter het object personen neerzetten zegt Visual Studio dat er een reeks methoden op zitten die allemaal erg interessant zijn. De code complete toont alle mogelijkheden van IQueryable en niet noodzakelijkerwijs wat de Linq provider kan.
Maar het werkt wel. Onder water zal Linq, in dit voorbeeld, alle personen ophalen die de tekst van ‘strNaam’ bevatten in de naam. Dat zal Linq in Linq to Objects het laatste stapje uitvoeren: Take(100).
(Dit is overigens een fictief voorbeeld. Onze provider heeft wel Take maar dit is als voorbeeld wat makkelijker uit te leggen dat de problematiek die wij tegen kwamen).

Oftewel: Linq gaat transparant en zonder waarschuwing van de ene Linq provider naar de andere om je query te kunnen uitvoeren. Dat is mooi maar ook link.
In de ontwikkelomgeving zal dit dus prima werken totdat je gaat testen met een database waar velen male meer personen in de database staat. Want dan wordt bijna je hele tabel in je geheugen gelezen bij het invoeren van één letter.


Werken met ?
Kijk dan bij onze mogelijkheden voor zowel starters als ervaren engineers.


Categorieën: Development, .Net

Tags: , , , , , ,


Reacties (4)

  • Een goed punt, Ivo. Zo zie je dat het abstract en implementatie-onafhankelijk definiëren van je logica een mooi uitganspunt is maar dat je in de praktijk toch altijd rekening moet houden met je onderliggende implementatie.

    Het meest vreemde voorbeeld hiervan dat ik ooit ben tegengekomen is wel query-optimalisatie in databases. Het feit dat bepaalde queries in bepaalde versies van zekere DBMS’en sneller lopen als je je joins en je constraints een beetje husselt toont al aan dat een hoog abstracte omschrijving in een taal als SQL een heel mooi uitgangspunt is maar dat er toch vaak implementatie-specifieke effecten doordruppelen naar je hoog abstracte laag toe.

    Jammer, maar een fact of life helaas.

    Geplaatst op 30 november 2009 om 22:52 Permalink

  • David schreef:

    Dit is niet alleen een probleem met Linq, maar ook met database communicatie.. hoe vaak gebeurd het niet dat alle data uit een database worden gehaald, omgezet naar objecten en uiteindelijk gefilterd?
    Ok, het is voor een deel de verantwoordelijkheid van de Linq-provider om dit op te lossen (dat filter op de server uitvoeren als dat al mogelijk is bij ActiveDirectory), maar aan de andere kant moet je er als programmeur ook niet helemaal van uitgaan dat de libraries die je gebruikt volledig veilig zijn…

    Geplaatst op 30 november 2009 om 10:06 Permalink

    • Ivo Limmen schreef:

      Ik blijk me te hebben vergist in AD: daar is geen provider voor (Met dank aan Tom Kemper voor het opmerken van de fout).
      Klopt: we kwamen dit probleem ook tegen in de database. We werken met een Oracle provider die is gemaakt door Microsoft en is letter voorbeeld code, er zitten dus een hoop bugs en missende functionaliteit in. Sterker nog: we hebben niet eens documentatie van wat de provider implementeert!

      Geplaatst op 30 november 2009 om 10:21 Permalink

      • Tom schreef:

        Ik blijf het lastig vinden om Linq hier zo maar de schuld van te geven.

        Ik weet niet hoe precies een custom Linqprovider implementatie werkt, maar ik denk dat het terecht is om Linq als een soort interface te zien in dit geval (al zij het waarschijnlijk in de praktijk geen letterlijke .Net interface declaratie).

        In het algemeen zal Intellisense immers ook niet kunnen voorspellen of er een “throw new NotImplementedException()” achter een methode schuilt.

        In dit specifieke geval vermoed ik dat onze provider wel een implementatie van Take bevat, maar toevallig een hele slechte (eentje die namelijk eerst de query tot dan toe uitvoert, en dan maar delegeert aan Linq-to-Objects).

        Hoe dan ook vrees ik dat we hier onder verschillende hypotheses werken. Jij zegt dat de Linq-extensions van provider switchen, terwijl ik vermoed dat het de provider in kwestie is die stiekem bezig is.

        Mocht inderdaad Linq intern een soort ‘try-catch’ structuur bezitten waarin het terugvalt op Linq-to-objects, dan is dat inderdaad vrij ‘leugenachtig’ te noemen. Ik dacht echter dat hier expliciet een ‘ToList()’ call voor nodig was.

        Geplaatst op 30 november 2009 om 16:45 Permalink