2007. április havi bejegyzések

Verziókáosz

Korábban már kétszer írtam arról, hogy a Microsoftnak nem erőssége az egyes termékek verzióinak számozása, így nem meglepő, hogy sokan nem tudják követni, hogy a .NET keretrendszer és pereputtya éppen melyik verziónál tart. Az alábbi táblázat jó referenciaként szolgálhat:

  2002. 2003. 2005. 2006. 2007. ?
Fejlesztőeszköz VS.NET (7.0) VS.NET 2003 (7.1) VS 2005 (8.0) VS 2005 (8.0)
+ W*F Extension-ök
VS "Orcas" (9.0)
C# nyelv 1.0 1.1 2.0 2.0 3.0
.NET Framework 1.0 1.1 2.0 3.0 3.5
Common Language Runtime 1.0 1.1 2.0 2.0 2.0

A lényeg: a VS következő, "Orcas" változatával együtt lesz új C# fordító és új .NET Framework is, de nem lesz új CLR. Legalábbis most így látszik…

 

Technorati tags: , , ,

Adatok csoportosítása és megjelenítése – ASP.NET + Dlinq

A feladat: adott a Northwind adatbázis Customers táblája, amiből az adatokat csoportosítva, csoportonként megszámlálva kell megjeleníteni egy weblapon, hierarchikus listában.

Először is, kell hozzá egy pofás Dlinq lekérdezés, amihez a szükséges osztályokat SqlMetal-lal legyártottuk:

    var query = ( from c in dc.Customers
                  group c by c.Country into g
                  select new
                  {
                    Country = g.First().Country,
                    Customers = g.OrderBy( p => p.ContactName ),
                    CustomerCount = g.Count()
                  }
).OrderByDescending( r => r.CustomerCount ).ThenBy( r => r.Country );

Igazi állatorvosi ló a query-k világában! Így kell olvasni:

Vedd a Customers táblát, csoportosítsd be a sorait a Country mező szerint és a csoportokat nevezd g-nek, majd minden csoportnak hozz létre egy új objektumot (aminek a típusát nem mondom meg, csinálj újat), melynek legyen három mezője:

  • A Country mező értéke legyen a csoport első elemének Country mezőjének értéke,
  • A Customers mező legyen egy tömb, elemei egyezzenek meg a csoport elemeivel, csak épp a ContactName mező szerint rendezve,
  • A CustomerCount mező pedig tartalmazza a csoport elemeinek számát,

Ezek után rendezd az eredményt a CustomerCount mező szerint csökkenő sorrendbe, azon belül pedig a Country mező szerint növekvő sorrendbe.

A legszebb az egészben, hogy akkor is működik, ha több táblát kapcsolunk össze és a Customers helyére például egy Orders tömböt teszünk.

Ha mindezt szép HTML kimenettel akarjuk megjeleníteni, akkor két egymásba ágyazott Repeatert használhatunk. Ha a szép kód annyira nem fontos, akkor szinte bármilyen vezérlő megteszi, hiszen egyszerű adatkötésről van szó:

    <asp:Repeater ID="repCountries" runat="server">
        <HeaderTemplate><ul></HeaderTemplate>
        <ItemTemplate>
            <li>
                <%# Eval( "Country" ) %> (<%# Eval( "CustomerCount" ) %> db)
                <asp:Repeater runat="server" DataSource='<%# Eval( "Customers" ) %>'>
                    <HeaderTemplate><ul></HeaderTemplate>
                    <ItemTemplate>
                        <li><%# Eval( "ContactName" ) %></li>
                    </ItemTemplate>
                    <FooterTemplate></ul></FooterTemplate>
                </asp:Repeater>
            </li>
        </ItemTemplate>
        <FooterTemplate></ul></FooterTemplate>
    </asp:Repeater>

Nem marad más hátra, mint az összes kódot összerakni egybe:

    string connStr = @"Data Source=.;Initial Catalog=Northwind;Integrated Security=True;";

    Northwind dc = new Northwind( connStr );
    var query = ( from c in dc.Customers
                  group c by c.Country into g
                  select new
                  {
                     Country = g.First().Country,
                     Customers = g.OrderBy( p => p.ContactName ),
                     CustomerCount = g.Count()
                  }
).OrderByDescending( r => r.CustomerCount ).ThenBy( r => r.Country ); this.repCountries.DataSource = query; this.repCountries.DataBind();

Már lehet is tesztelni!

 

Mindössze két apró problémám van az egésszel:

1. Bár egyetlen táblán dolgozunk, az adatbázis műveletek száma = országok száma + 1. Sajnos ha egyszerű adatkötést használunk, akkor a hagyományos ADO.NET-tel sem tudjuk egyszerűbben megoldani (ha valaki meg tudja, írja meg!).

  • Az országokhoz kapcsolódóak nem túl bonyolult lekérdezések, ezt kapja meg az adatbázis:
    exec sp_executesql N'SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], 
[t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode],
[t0].[Country], [t0].[Phone], [t0].[Fax]
FROM [Customers] AS [t0]
WHERE ((@x1 IS NULL) AND ([t0].[Country] IS NULL)) OR
((@x1 IS NOT NULL) AND ([t0].[Country] IS NOT NULL) AND (@x1 = [t0].[Country]))
ORDER BY [t0].[ContactName]',N'@x1 nvarchar(3)',@x1=N'USA'
  • Engem az a bizonyos +1, az első lekérdezés jobban zavar, ami szerintem elég randára sikeredett (bár a végrehajtási tervben már szebbnek látszik):
    SELECT [t4].[value] AS [Country], [t4].[Country] AS [Country2], [t4].[CustomerCount]
    FROM (
        SELECT (
            SELECT [t3].[Country]
            FROM (
                SELECT TOP 1 [t2].[Country]
                FROM [Customers] AS [t2]
                WHERE (([t1].[Country] IS NULL) AND ([t2].[Country] IS NULL)) OR 
(([t1].[Country] IS NOT NULL) AND ([t2].[Country] IS NOT NULL) AND ([t1].[Country] = [t2].[Country])) ) AS [t3] ) AS [value], [t1].[Country], [t1].[value] AS [CustomerCount] FROM ( SELECT COUNT(*) AS [value], [t0].[Country] FROM [Customers] AS [t0] GROUP BY [t0].[Country] ) AS [t1] ) AS [t4] ORDER BY [t4].[CustomerCount] DESC, [t4].[value]

2. Az eredményt nem lehet közvetlenül TreeView-hoz kötni, mert a TreeViewnak hierarchikus adatforrásra van szüksége. Azt sem ördöngősség megírni, de még több munka és nem kapunk hozzá semmilyen VS támogatást. Aki még nem írt hierarchikus adatforrást, az lehet, hogy hamarabb készen lesz, ha végigiterál az eredményhalmazon és kódból tölti fel a fa csomópontjait.

Ezek után szerintem mindenki döntse el maga, hogy használja-e a Dlinq-et vagy sem, de aki teheti, írja meg a véleményét, mert kíváncsi vagyok!

Technorati tags: LINQ, DLINQ, ASP.NET

Dlinq alapok és SqlMetal, a Dlinq rabszolga

A márciusi Orcas CTP-t elindítva eleinte nehézkesnek tűnik a LINQ-kel történő ismerkedés, mert a 2006. májusi előzetestől eltérően itt már nincs külön LINQ projekt típus a Visual Studioban. 

Íme a szükséges első lépések:

  1. Hozzunk létre egy új konzol alkalmazást, például LinqApp néven.
  2. Referenciaként adjuk a projekthez a System.Data.Linq.dll-t, amit a C:WINDOWSMicrosoft.NETFrameworkv3.5.20209 mappában fogunk megtalálni. Érdekes módon a VS az Add Reference ablak .NET fülén nem sorolja fel, ezért használjuk a Browse fület és keressük meg a DLL-t.
  3. Júzingoljuk a System.Data.Linq névteret.

Miután ezzel így megvagyunk, bele is vethetjük magunkat a DLINQ-be. Ehhez először is adatbázisra lesz szükségünk, legyen a jól ismert Northwind, ami innen tölthető le.

Ahhoz, hogy a Northwindben lévő partner adatokat elérhessük, készítsünk egy Customer osztályt, ami C# szinten definiál egy partnert. A partnernek legyen ContactName, ContactTitle és City tulajdonsága, ezeket ugyanis tartalmazza az adatbázisban lévő Customers tábla.

Fontos, hogy az osztályunkat fel kell címkéznünk attribútumokkal, melyek azt jelzik, hogy ez az osztály melyik táblához tartozik és az egyes tulajdonságok a tábla mely oszlopához tartoznak. Ehhez a Table és Column attribútumokat használhatjuk, melyek a System.Data.Linq névtérben találhatóak. (Az Orcas VPC-ben lévő MSDN-ben megtalálhatjuk az osztályok összes tulajdonságát, itt csak a legegyszerűbbeket fogjuk használni.)

Ha mindent jól csináltunk, az osztály végül valahogy így fest, kihasználva az automatikus property gyártás új szintaxisát:

    using System;
    using System.Data.Linq;

    namespace LinqApp
    {
        [Table( Name = "Customers" )]
        class Customer
        {
            [Column]
            public string ContactName { get; set; }

            [Column]
            public string ContactTitle { get; set; }

            [Column]
            public string City { get; set; }
        }
    }

Definiáltuk a "sémát", már csak adatokkal kellene feltöltenünk. Ehhez persze kell egy connection string:

    string connStr = @"Data Source=.;Initial Catalog=Northwind;Integrated Security=True;";

Az objektumtér és az adatbázis között a kapcsolatot egy DataContext példány teremti meg, amely hasonló az ADO.NET Connection objektumához, ez ismeri például a connection stringet:

    DataContext dc = new DataContext( connStr );

A DataContext ojjektumtól kérhetjük el a táblákat is:

    Table<Customer> customers = dc.GetTable<Customer>();

A táblákon pedig lekérdezéseket definiálhatunk:

    var query = from c in customers        
                orderby c.ContactName
                where c.City == "London"
                select c;

A lekérdezés eredményét pedig feldolgozhatjuk, például így:

    foreach( Customer c in query )
    {
        Console.WriteLine( "{0}t{1}", c.ContactName, c.ContactTitle );
    }

Előfordulhat, hogy fordítás közben a következő hibaüzenetet kapjuk:

‘System.Data.Linq.Table<LinqApp.Customer>’ does not contain a definition for ‘OrderBy’ and no extension method ‘OrderBy’ accepting a first argument of type ‘System.Data.Linq.Table<LinqApp.Customer>’ could be found (are you missing a using directive or an assembly reference?)

A megoldás:

    using System.Linq;

Ezzel készen is van az első DLINQ alkalmazásunk!

 

Néhány dolgot mindenképp érteni kell:

1. Mi az a var, oda a típusosság?

Szó sincs róla! A var kulcsszó annyit jelent, hogy nem mondom meg a típust, kedves fordító, találd ki a jobb oldalról. A fordító tehát olyan típusúvá fogja tenni query változót, amilyennek azt a lekérdezés meghatározza. A lekérdezések egyébként System.Linq.IQueryable típusúak, ami lényegében egy felturbózott IEnumerable, ezért lehet forícselni.

2. Mikor fut a lekérdezés?

A LINQ egyik alapelve az úgynevezett deferred execution, azaz késleltetett lekérdezés, melynek lényege, hogy a lekérdezések nem akkor futnak, amikor definiáljuk őket, hanem amikor az eredményüket fel akarjuk dolgozni. Mivel a lekérdezések IEnumerable származékok, valójában akkor futnak, amikor végigiterálunk rajtuk.

Ezt egyébként a VS is tudja! Tessék betenni egy breakpointot a var és a foreach közé és megnézni a query változót az Autos ablakban! Az eredmények kibontása előtt ott a figyelmeztetés:

Expanding the Results View will enumerate the IEnumerable.

És valóban, ha SQL Profilerrel megnézzük, valóban csak akkor kap kérést az adatbázis szerver.

3. Milyen SQL utasításokra fordul a lekérdezés?

Ha nem akarunk SQL Profilerezni, akkor legegyszerűbben úgy tudhatjuk meg, hogy mit kell az adatbázisnak megennie, ha használjuk a DataContext Log tulajdonságát, aminek bármilyen TextWritert átadhatunk:

    dc.Log = Console.Out;

Jelen esetben ezt kapja meg az SQL Server:

    SELECT [t0].[ContactName], [t0].[ContactTitle], [t0].[City]
    FROM [Customers] AS [t0]
    WHERE [t0].[City] = @p0
ORDER BY [t0].[ContactName] -- @p0: Input NVarChar (Size = 6; Prec = 0; Scale = 0) NOT NULL [London]

Az IQueryable belső reprezentációja egy Expression objektum, amely az ún expression tree-t tartalmazza, tehát akár ezt is írhattuk volna (ha esetleg kedvelnénk a lambda expressionöket):

    var query = customers.OrderBy( c => c.ContactName ).Where( c => (c.City == "London") );

4. Tényleg minden táblához kell írnom egy osztályt?

Osztály kell, de nem kell megírni, van ugyanis osztálygyártó rabszolga, úgy hívják: SqlMetal.exe. Ez a kis jószág a C:Program FilesMicrosoft Visual Studio 9.0SDKv3.5Bin mappában található, ami sajnos nincs bent a PATH-ban a március CTP image-ben, így vagy hozzávesszük, vagy nyitunk egy SDK command promptot és belépünk a Bin almappába. Az alkalmazás egyékbént egyetlen 98KB-os exe, amit át is másolhatunk a projekt mappánkba.

Van neki jó sok paramétere, a mi példánkban használhatjuk így:

    SqlMetal.exe /server:. /database:Northwind /code:Northwind.cs /namespace:LinqAppMetal /pluralize

Azt hiszem minden kapcsoló magáért beszél, a gyakorlatban még valószínűleg a /sprocs kapcsolót fogjuk használni, amivel tárolt eljárások hívását is egy csapásra metódus hívásokká burkolhatjuk. A generált fájlban találunk egy DataContextből származó Northwind osztályt, illetve minden egyes táblának egy saját osztályt. Érdemes megnézni, hogy miben más a generált Customer osztály, ahhoz képest, amit mi írtunk!

Az SqlMetal által generált 2599 sornyi forráskódot felhasználva a következőre egyszerűsödik az adatbázis lekérdezésünk:

    Northwind dc = new Northwind( connStr );
    var query = from c in dc.Customers
                orderby c.ContactName
                where c.City == "London"
                select c;

Így már szerintem sokkal barátságosabb a feladat.

Technorati tags: ,

A nap jó híre

A nap jó hírét Somának köszönhetjük: az Expression termékcsalád bekerül az MSDN előfizetésbe. Épp ideje volt, hogy a Microsoft kiköszörülje ezt a csorbát, hogy előállnak egy új fejlesztőknek szánt eszközzel, csak épp nem teszik be a fejlesztőknek szánt előfizetői csomagba. Nos, úgy tűnik meghallották ezeket a sirámokat és most megtörtént. Pontosabban fogalmazva az Expression Web és az Expression Blend kerül csak be az MSDN-be, az Expression Media és az Expression Design nem, azok ugyanis a Microsoft pozícionálásában elsősorban nem fejlesztőeszközök.

Kipróbáltam, valóban megjelent az Expression Web az MSDNAA letöltő oldalon és Volume License termékkulcsot is sikerült igényelni hozzá. A Blendnek még nyoma sincs.

Egyébként mindenképp érdemes legalább egyszer kipróbálni az Expression Webet. Elsőre teljesen FrontPage, pardon SharePoint Designer feeling, de aztán az ember rájön, hogy itt sokkal jobban rámentek két dologra:

  • A termék nagyon támogatja a szabványos, CSS alapú tervezést, újabb toolboxok segítik a CSS osztályok egymásra hatásának megértését és a lehetséges stílus tulajdonságok beállítását. Ez valóban tud segíteni.
  • A termék ismeri az ASP.NET-es kontrollokat, master page-eket, theme-eket. Egyszerűen rá lehet nyitni vele egy ASP.NET web site mappára.
    Na azért ebben is sikerült hiányosságot találnunk: master page-re elhelyezett tildés URL-re mutató, runat=server attribútummal ellátott LINK tag-et nem tudott értelmezni, ami azért ciki, mert az mutatott volna a CSS-re. Nesze neked CSS dizájner…

Akit pedig mindez nem hatott meg, annak pedig azért érdemes kipróbálnia, hogy lássa, mi mindent fog tudni a Visual Studio "Orcas"-ba integrált webtervező eszköz. A Microsoft fejlesztői rájöttek, hogy nem kellene minden webhez kapcsolódó termékbe más dizájnert integrálni, ehelyett készítettek egy tutit (Sapphire kódnéven) és ezt integrálták az Expression Webbe és a VS Orcasba is. Bővebb információkat és képernyőfotókat Scotty és Mikhail Arkhipov blogjában lehet találni.

Akinek nincs MSDN előfizetése és nem fér hozzá MSDNAA-hoz, annak a 180 napos trial lehet megoldás a kísérletezésre.

 

Technorati tags: , ,

MVP, azaz Most Valuable Professional

Az MVP programot a Microsoft sok évvel ezelőtt azért hozta létre, hogy valamilyen formában díjazza azokat, akik aktívan hozzájárulnak a Microsoft technológiák terjesztéséhez és teszik ezt elsősorban másokat segítve önzetlenül, közösségi csatornákon, fórumokon, hírcsoportokon, levlistákon, blogokon keresztül. Az MVP-k rendkívül értékes szakemberek, hiszen nem fizetett Microsoft alkalmazottak, így őszintén és nyíltan mondhatják el a véleményüken bármelyik termékről vagy technológiáról, ráadásul a szükséges szakmai tudásuk is megvan hozzá.

Magyarországon az MVP program 2004-ben indult be, elsősorban üzemeltetési területen járatos szakemberekkel és azóta – köszönhetően részben az MVP Leadeknek, Stroh Edinának és Budai Péternek – töretlenül bővül. Az MVP-kkel először szakmai fórumokon, a TechnetKlubon és a devPORTALon lehetett találkozni, később egyre több webcast és konferencia előadója került ki az MVP-k közül.

Ezen cikk apropóját az adja, hogy lezárult egy újabb MVP választási ciklus, így április 1-jétől új tagok kerültek a programba. Szerettem volna összegyűjteni az aktuális teljes listát, de sajnos sem a hivatalos oldalon, sem a magyar oldalon nem találtam meg mindenkit. smile_sad

A jó hír az, hogy folyamatosan bővül a fejlesztői MVP-k listája is, amiben például Albert István és Soci is megtalálható. Ha úgy érzed, hogy szívesen tennél a fejlesztői közösségért és nem bánnád, ha ezt a Microsoft is elismerné, csak rajta, fórumozz, bloggolj, segíts másokon! Teheted mindezt például a devPORTALon, ha pedig szakmai segítségre, forrásokra van szükséged ehhez, keresd Bátorfi Zsoltot, ő a te embered!

Orcas MSDN konferencia témák

Aki figyelmesen elolvasta a márciusi MSDN hírlevelet, annak biztosan feltűnt, hogy május 24-én MSDN konferencia lesz a .NET 3.5 platformról és a Visual Studio következő, "Orcas" kódnevű változatáról. Természetesen vannak elképzeléseink, hogy miről fog szólni a rendezvény, most mégis kísérletet teszek arra, hogy a szervezésbe bevonjam a fejlesztői közösséget is: itt a blogban hozzászólásként jelezzétek, hogy miről szeretnétek hallani!

Írjatok még akkor is, ha teljesen nyilvánvaló, vagy éppen látszólag apró témáról van szó. Minden véleményt és javaslatot elolvasunk és figyelembe veszünk, hallassátok a hangotokat! smile_regular

Magyarországi Web Konferencia 2007

Véget ért az idei Web Konferencia, aki ott volt szombaton, biztos nem sajnálja, hogy erre áldozta a fél hétvégéjét. Nagyon jó szakmai tartalom jött össze, ami részben az előadóknak, részben pedig a szervezőknek – PP-nek, Gobának és a többieknek – köszönhető. Nem meglepő módon az AJAX-é volt a főszerep, a 24 előadás többségében előfordult, jó volt látni, hogy minden technológia lépést tart a Web 2.0-val, közösek a problémás és közösek a célok.

Bátorfi Zsolti megint kemény fába vágta a fejszéjét és elsőként beszélt kis hazánkban a WPF/E technológiáról, valamint egy másik előadásban a nagy testvér WPF-ről is. Aki lemaradt sajnálhatja, de elolvashatja Bazso online közvetítését az eseményről, illetve a NetAcademia április 24-i MesterQrzusán közvetlenül is kapcsolatba kerülhet a technológiával.

Meglepően nagy érdeklődés volt a Böngésző- és szerver független AJAX programozás előadásra, remélem a résztvevők nem csalódtak sem a témában, sem az előadóban. A kapcsolódó PPT és demó fájlokat feltöltöttem a devPORTALra. Szerintem nagyon ütős az AJAX Library és az előadás utáni rövid beszélgetésből az derült ki számomra, hogy nem csak én gondolom így.

Az ASP.NET alkalmazások AJAX-osítása előadáson lényegesen kevesebben voltak, ami az előadás és a résztvevők paramétereit figyelembe véve nem volt meglepő. A Microsoft Web Platformmal kapcsolatban érdeklődők számára Nacsa Sándor nagyon jó anyagot állított össze a http://www.microsoft.com/hun/web07/ címen, ami a tervek szerint rendszeresen frissülni fog, érdemes időnként visszalátogatni. Aki pedig az előadás PPT-jére vagy demó fájljaira kíváncsi, a devPORTALon megtalálja őket.

Összességében nagyon jó élmény volt résztvenni a konferencián, egyedül azt sajnálom, hogy kevés időm akadt beszélgetni a résztvevőkkel, ezért nagyon hálás lennék, ha itt a blogban vagy e-mailben bármiféle visszajelzést kaphatnék akár a technológiáról, akár az előadásról. Köszönöm!