2007. május havi bejegyzések

DLINQ: Egyszerű tárolt eljárások esete az MSDN-nel

Egyszerűnek tekinthetjük az alábbi, elég tipikusnak mondható tárolt eljárást, ami visszaadja egy adott tábla rekordjainak számát:

    CREATE PROCEDURE dbo.GetCustomerCount
    AS
        SELECT Count(*) FROM Customers

Amikor megpróbáljuk meghívni, ugyanúgy járunk el, mint máskor, rádobjuk a tárolt eljárást a Visual Studio O/R Designerére, ami generál nekünk egy éppen megfelelő metódust. Szinte eláll a szívünk, amikor meglátjuk az így előállt C# metódust és már hívjuk is lelkesen, hiszen int a visszatérési érték:

    NorthwindDataContext dc = new NorthwindDataContext();
    int i = dc.GetCustomerCount();
    Console.WriteLine( i );

Bár a tárolt eljárás szinte művészien tökéletes, szomorúan konstatáljuk, hogy bizony mindig nullát ad vissza. Nézzük meg a generált metódus belsejét:

    [StoredProcedure( Name = "dbo.GetCustomerCount" )]
    public int GetCustomerCount()
    {
        IExecuteResults result = this.ExecuteMethodCall(
            this,
            (MethodInfo) MethodInfo.GetCurrentMethod() );
        return ( (int) ( result.ReturnValue ) );
    }

A kérdés – amire az MSDN-ből aligha kapunk választ a mostani béta változatban -, hogy mi az az IExecuteResults és mit tud a ReturnValue tulajdonsága? Némi Reflectorozással odáig sikerült eljutnom, hogy a DataContext.ExecuteMethodCall meghívja az aktuális provider ExecuteNonQuery metódusát, de mivel az is interfész alapú (IProvider), így az implementációval először nem sokáig jutottam. (Ezen a ponton arra tippeltem, hogy ez az ExecuteNonQuery ugyanúgy viselkedik, mint az IDbCommand esetén és az "érintett sorok" – rows affected – számát adja vissza. Mint kiderült nem egészen…)

Aztán tovább ásva megtaláltam a System.Data.Linq.SqlClient.SqlProvider osztályt, ahol az ExecuteNonQuery egy SqlExecuteResults típussal tér vissza, ami implementálja az IExecuteResults interfészt. Már csak az maradt kérdés, hogy hogyan kap értéket a ReturnValue tulajdonság? A konstruktorból kiderül, hogy a @RETURN_VALUE paramétertől.

Na de ki beszél itt SQL paraméterről, hiszen ennek a tárolt eljárásnak nincs se input, se output paramétere! Nosza kérdezzük meg, mi megy az adatbázisba, amihez használhatjuk a DataContext.Log tulajdonságát. Az eredmény:

    EXEC @RETURN_VALUE = [dbo].[GetCustomerCount]
    -- @RETURN_VALUE: Output Int (Size = 0; Prec = 0; Scale = 0) NOT NULL []

Hűha! Irány az SQL Server Books Online, hányféleképpen lehet beállítani egy tárolt eljárás visszatérési értékét? Nekem SELECT-tel nem sikerült, maradt a RETURN, amihez át kellett írni a tárolt eljárást, például így:

    DECLARE @Result int
    SELECT @Result = Count(*) FROM Customers
    RETURN @Result

Ez engem zavar, ezért kedves SQL guruk, mondjatok valami egyszerűbbet!

Ami pedig az MSDN-t illeti, egyetlen rövid mondat rengeteg időt megspórolhatott volna. Persze, tudom, béta termék, meg ez csak egy metódus a sok közül, de akkor is. Gondoltam egyet és megkeresetem az ExecuteMethodCall oldalát az MSDN Wikiben: abban reménykedtem, hogy ha ide megírom a felfedezéseimet, az majd segít másoknak és valamilyen formában bekerül az RTM dokumentációba. Nos, erről lepattantam, egyrészt mert úgy látszik a béta dokumentációhoz nem lehet hozzáírni, másrészt pedig ennek a metódusnak a leírása angolul nem található meg, csak japánul smile_sniff Ez remélem átmeneti bug és nem feature smile_sad

 

Technorati tags:
Reklámok

DLINQ: Tárolt eljárások visszatérési típusai (VS trükk)

DLINQ-ből tárolt eljárásokat hívni pofon egyszerű: ráncigálni kell egy kicsit a VS dizájnert, míg ki nem pottyan egy metódus, aminek a szintaktikája éppen a tárolt eljáráséval egyezik meg. Az viszont nagyon nem mindegy, hogy a dizájnerben hogyan kattintgatunk, és mivel a jelenlegi bétában nem sok visszajelzést kapunk, íme egy trükk!

Példaként használjuk a Northwind adatbázist, és akarjuk meghívni a következő nagy bonyolultságú tárolt eljárást:

    CREATE PROCEDURE dbo.GetCustomersInCity
    (
        @City nvarchar( 15 )
    )
    AS
        SELECT * 
        FROM Customers
        WHERE City = @City

Van tehát egy string bemenő paraméterünk, válaszként pedig a Customers tábla rekordjait adjuk vissza. Ennek burkolására úgy készíthetünk DLINQ-es metódust, hogy a Visual Studio "Orcas" O/R Designerében dolgozgatunk, ami akkor jelenik meg, ha Linq to SQL File típusú elemet adunk a projekthez. A dizájner mellé nyissuk ki a Server Explorert, majd ragadjuk meg a tárolt eljárásunkat és dobjuk a dizájner jobb felére, mert az a metódusok helye. Ennek eredménye a következő metódus lesz a DataContext osztályunkban (kicsit kipofozva és leegyszerűsítve):

    [StoredProcedure( Name="dbo.GetCustomersInCity" )]
    public IEnumerable<GetCustomersInCity> GetCustomersInCity( 
        [Parameter( Name="@City" )] string City )
    {
        IQueryResults<GetCustomersInCity> result = 
            this.ExecuteMethodCall<GetCustomersInCity>( 
                this, 
                (MethodInfo) MethodInfo.GetCurrentMethod(), 
                City ); 
        return (IEnumerable<GetCustomersInCity>) result;
    }

A problémát a piros aláhúzott típusok jelentik: a VS lelkesen generált egy új osztályt, aminek olyan tulajdonságai vannak, mint amilyen oszlopokkal a tárolt eljárás visszatér és azt elnevezte GetCustomersInCity-nek. Hagyjuk figyelmen kívül egy pillanatra ennek a típusnak a közel sem bájos nevét és koncentráljunk inkább arra, hogy ez nem a Customer típus, hanem egy ugyanolyan szerkezetű, de másik típus! Ugyanez történik akkor is, ha a dizájnerben már van Customer, a VS nem képes rájönni, hogy a kettő szemantikailag azonos.

Lelkesen felcsaphatjuk a Properties ablakot és örülhetünk, amikor meglátjuk, hogy létezik egy Return Type nevű tulajdonság, aminek az értéke éppen (Auto-generated Type), ám az örömünk hamar elillan, amikor rájövünk, hogy ez bizony read-only.

A rejtély kulcsa abban rejlik, hogy nem mindegy, hova ejtjük a Server Explorerből kifogott tárolt eljárást! Előbb tegyük be a Customers táblát a dizájner bal felére, majd utána fogjuk meg a tárolt eljárást és ne a dizájner jobb felére tegyük, hanem a Customers tábla felett engedjük el az egérgombot. Voila, a fenti kódrészletben az aláhúzott generált típus helyett mindenhol Customer fog szerepelni!

Még egy tanulság a fenti kódrészletből: ha azt akarjuk, hogy a metódus paramétereinek casingjére az FxCop ne panaszkodjon, akkor használjunk a tárolt eljárásokban kisbetűs paraméter neveket, különben kénytelen leszünk módosítani a Parameter attribútum Name tulajdonságát.

 

Technorati tags:

IE Developer Toolbar RTM

El sem hiszem, hogy ez a kis segédeszköz elkészült! 2005 óta használjuk a béta verziókat, már fel sem tűnt, hogy nem RTM. Korábban már írtam az Internet Explorer Developer Toolbarról, ami az IE-be beépülve segíti a webfejlesztők életét a következő funkciókkal:

  • Explore and modify the document object model (DOM) of a Web page.
  • Locate and select specific elements on a Web page through a variety of techniques.
  • Selectively disable Internet Explorer settings.
  • View HTML object class names, ID’s, and details such as link paths, tab index values, and access keys.
  • Outline tables, table cells, images, or selected tags.
  • Validate HTML, CSS, WAI, and RSS web feed links.
  • Display image dimensions, file sizes, path information, and alternate (ALT) text.
  • Immediately resize the browser window to a new resolution.
  • Selectively clear the browser cache and saved cookies. Choose from all objects or those associated with a given domain.
  • Display a fully featured design ruler to help accurately align and measure objects on your pages.
  • Find the style rules used to set specific style values on an element.
  • View the formatted and syntax colored source of HTML and CSS.

Egyszóval szinte nélkülözhetetlen, tessék tehát letölteni és ha közel két év fejlesztés után még mindig maradt benne hiba, akkor a fórumban feedbackelni a fejlesztőknek. Csak referenciaként: a ma letölthető RTM verziószáma 1.00.2188.0.

 

Technorati tags:

CAS

Egy beszélgetés során ma szóba került a Code Access Security. Úgy látom, többnyire kétféle kép él a fejlesztők fejében a CAS-ról:

  1. A CAS egy világmegváltó találmány, amely majd forradalmasítja a rendszereink biztonságát. Kellene használnunk nekünk is, csak éppen nem tesszük, mert nem felel meg a céljainknak, nincs rá idő vagy pénz vagy nincs is rá szükségünk.
  2. A CAS túl bonyolult ahhoz, hogy használjuk, kerüljük el inkább a lehető legnagyobb ívben.

Talán mindkettő igaz, és fájdalom, de immár 7 éve többnyire csak kikapcsolva tudjuk elviselni. A szomorú valóság az, hogy a CAS egy hamvába halt kezdeményezés, egyszerűen azért, mert az üzemeltető nem tudja a jogosultságokat ésszerűen állítgatni, a fejlesztőtől pedig rengeteg többletmunkát igényel a korrekt implementáció. Túl sok kód, túl sok adminisztráció.

Hogyan lehetne felturbózni? Jól megválasztott jogosultságkészlettel és nagy adag eszközzel, ami segíti a kódolást és az üzemeltetést. Ide lehet írni, ha már vannak ilyenek, csak elsiklottam volna felettük.

 

Technorati tags:

Word 2007 és a szabványosság – a tuti megoldás

Vége a szabadságnak, vissza a néha szomorú valóságba!

Korábban már írtam arról, hogy a Word 2007-ben nem sikerült korrekten implementálni a MetaWeblog API newMediaObject függvényét. Az RD levlista segítségével sikerült ráakadnom a vonatkozó tudásbázis cikkre, amelyből kiderül, hogy valóban létezik a hiba:

According to the newMediaObject API, the blogid parameter should be of type string. Word 2007 incorrectly uses integer as the type for the blogid parameter.

Sőt, workaround is van rá, de még milyen! Íme a mindentudó megoldás:

WORKAROUND

To work around this issue, use other code to post the blog. You may be able to search the Internet for code examples that can be used in your situation. For example, perform a search for "newMediaObject" and "Word" for possible code samples.

Már csak a Google linket kellett volna odatenniük smile_wink A belső pletykák szerint az SP1-ben kijavítják ezt a hibát.

 

Technorati tags: ,