Ha már (no name) volt olyan kedves, hogy küldött visszajelzést egy előző szösszenetemmel kapcsolatban – amit ez úton is köszönök neki – , nem tudom megállni, hogy ne kerüljön ide egy LINQ-kel kapcsolatos érdekesség. (Ez történik, ha az embert motiválják, motiválni kívánja a motiválókat ) De hogy ne legyen fenékig tejfel, nem C# 3.0-ban, hanem VB 9-ben! Hogy mindezt miért, mikor én is csak nagy ritkán kódolok Visual Basicben és akkor is mindig fáj, az maradjon a végére!
Ma azzal a feladattal találtam magam szemben, hogy el kellett dönteni, hogy egy új projektben hogyan generáljunk RSS-t és felmerült a LINQ is, pontosabban az XLINQ. Gyártsunk deszkamodellt!
Példaként vegyünk egy cikkeket tartalmazó Article nevű táblát a Teszt nevű adatbázisunkban:
- Id uniqueidentifier DEFAULT( NewSequentialId() )
- Title nvarchar(200)
- Body nvarchar(MAX)
- DateCreated datetime DEFAULT( GetDate() )
A feladat pedig az, hogy ebből kell a cikkek listáját RSS formában közzétenni. A 2006. májusi LINQ preview telepítése után létrehozhatunk egy LINQ Class Library típusú projektet, mégpedig VB-ben. Az SqlMetal parancssori eszköz segítségével le tudunk generálni két osztályt: az egyik lényegében az adatbázis kontextust fogja megvalósítani, a másik pedig az Article táblánkat modellező osztály lesz:
C:Program FilesLINQ PreviewBin>sqlmetal /server:. /database:teszt /language:vb /code:Teszt.vb
Az elkészült Teszt.vb fájlt adjuk hozzá a projektünkhöz, a kíváncsiak meg is nézhetik benne a Teszt és az Article osztályokat. Mit kell nézi rajtuk? Elsősorban az ősosztályokat és az attribútumokat.
Miután ezzel ilyen szépen megvagyunk, kérdezzük le a cikkeket időrendben, természetesen DLINQ-kel:
Dim conn As String = "Data Source=.;Initial Catalog=Teszt;Integrated Security=SSPI;" Dim db As New Teszt( conn ) Dim query = _ From a In db.Article _ Select a _ Order By a.DateCreated Descending
Aki kíváncsi az eredményre, írassa ki a konzolra:
For Each a As Article In query Console.WriteLine( a.Title ) Next
Aki a hagyományos típusokhoz vonzódik, csinálhat az eredményből például listát, ami éppoly típusos lesz, mint a fenti For Each:
Dim list As List(Of Article) = query.ToList(Of Article)()
OK, megvannak az adataink, készítsünk belőlük RSS-t, ami ugyebár XML-t jelent. Ha C#-ban kódolnánk, akkor lehetne használni az XDocument, XElement és XAttribute típusokat, remek példái annak, hogy mi történik, ha valaki úgy tervezi az osztályait, hogy előre látja, hogyan akarják majd használni.
A VB fordító azonban – és ma ezért kódoltam VB-ben – képes közvetlenül felismerni a forráskódban lévő XML-t! Közvetlenül, azaz idézőjelek nélkül! Ez egy értelmes és lefordítható kifejezés – lesz – VB 9-ben:
Dim darab = <alma szin="piros">2</alma>
Nem látszik, de típusosság van ám itt is! Egy függvény, amelynek String értékkel kell visszatérnie, megteheti azt például így:
Return <alma szin="piros">2</alma>.ToString()
Valójában implicit módon System.Xml.XLinq.XElement példányt hoztunk létre! Sőt, ezt megtehetjük úgy is, hogy az XML-be kódot teszünk, ez is érvényes kifejezés:
Dim ma = <today><%= DateTime.Now %></today> Console.WriteLine( ma )
Érdemes megfigyelni, hogy a dátum automatikusan XML-es dátum formátumban íródott be a tag-be:
<today>2007-03-09T17:10:06.546875</today>
Soha nem gondoltam, hogy valaha lelkesedni fogok a VB-ért, de ezt a feature-t nagyon szeretném a C#-ban! Na de a lelkesedést félretéve, ezzel a tudással már generálhatunk RSS-t. Hozzunk létre XML-t, abban LINQ kifejezést, abban megint XML-t, abban pedig megint LINQ-et. Követhető?
Ha a fenti kódot folytatjuk, akkor Stringben visszaadhatjuk a generált XML-t, amit például egy webalkalmazás publikálhat:
Return _ <?xml version="1.0" encoding="utf-8"?> <rss version="2.0" xmlns:cf="http://www.microsoft.com/schemas/rss/core/2005"> <channel> <title>Balássy György</title> <description>RD blog</description> <link>http://balassy.spaces.live.com/</link> <language>hu-HU</language> <pubDate><%= DateTime.Now %></pubDate> <lastBuildDate><%= DateTime.Now %></lastBuildDate> <ttl>180</ttl> <cf:listinfo> <cf:group element="category" label="Category"/> <cf:sort element="pubDate" label="Date" data-type="date" default="true"/> <cf:sort element="title" label="Title" data-type="string"/> </cf:listinfo> <%= _ From a In list _ Select _ <item> <title><%= a.Title %></title> <description><%= a.Body %></description> <guid isPermaLink="true">http://www.devportal.hu/Article.aspx?id=<%= a.Id %></guid> <pubDate><%= a.DateCreated %></pubDate> </item> _ %> </channel> </rss>.ToString()
Ha nem lenne szinezés a Studioban, valószínűleg sohasem bogarásznánk ki, hogy mi is történik itt, bár a kommentezés így sem fog ártani. A rossz hír, hogy mindez C#-ban még áttekinthetetlenebb lenne, mert ott minden XML elem létrehozásához inline meg kellene hívnunk az XElement konstruktorát.
Jótanácsok azoknak akik ismerkednének az XLinq-kel (a 2006. májusi verzió alapján):
- Még nem tökéletes az IntelliSense, nem kell mindig elhinni, amit felkínál.
- Az utasítás elválasztó aláhúzás (_) karakterre nagyon kell figyelni, ki kell tenni és előtte legyen szóköz.
- Aki kézzel akarja megírni a táblát reprezentáló osztályt, figyeljen arra, hogy VB-ben az attribútumokat a nyelvi elemmel együtt kell definiálni, ha tehát külön sorba írjuk őket, akkor kell a sor végére aláhúzás karakter.
- A Studio folyamatosan fordítja a kódot, miközben írjuk. Ha aláhúz valamit, az valójában fordítási hibát jelent, hihetünk neki.
Csak nekem tetszik, vagy ez más szerint is tényleg ütős?
Ha a Use my profile information berakta volna a nevet, akkor lett volna ott. :)Ez az inline xml nekem az XQueryből ismerős, jópofa dolog, kár, hogy nem lesz a C#-ban (bár lehet, hogy ezt is kivinnyogják, mint annak idején az Edit and Continue-t). Lassan kezd olyan olvashatatlan lenni a VB mint a PERL. Write only language:)Kár, hogy a tudása viszont még messze van attól. De nem is ugyanarra a koponyaűrtartalomra és mentalitásra fejlesztik.Jöhet még sok LINQ cikk. 🙂