Tracking profile importálása szkriptből

Nincs jobb, mint amikor az embernek van egy olyan szkriptje kéznél, ami egyszerűen és átláthatóan teszi a dolgát és igazán megkönnyíti a fejlesztő munkáját. Az egyik gyakori feladat az adatbázis létrehozása, amit két módon lehet megtenni:

  • Adatbázis attachelésével. Ez egyszerű, csak éppen a változtatásokat nehéz követni benne fejlesztés közben. Tipikusan akkor választja az ember ezt a megoldást, amikor azt hiszi, hogy ezzel kevesebb gondja lesz, de később kiderül, hogy mégse.
  • SQL szkriptekkel. Ez kényelmesen szerkeszthető és verzionálható, csak éppen az a kérdés, hogyan fognak egyszerűen lefutni az SQL szkriptek.

Az utóbbi az érdekesebb, hogyan futtatunk SQL szkripteket parancssorból? Korábban az osql.exe vagy az isql.exe volt a jópajtás, az SQL Server 2005-től kezdve ezek helyét átvette az SQLCMD.

Például ha Windows Workflow Foundationt használunk, valószínűleg szükségünk lesz tracking és persistence adatbázisokra, amikhez csak az SQL szkripteket kapjuk a Microsofttól. Nosza gyűrjük be az alábbi néhány sort egy cmd fájlba és máris lehet duplán kattintva adatbázist gyártani (eltördeltem a hosszú sorokat):

    SQLCMD -S .SqlExpress -Q "CREATE DATABASE MyDB"

    SQLCMD -S .SqlExpress -d MyDB -i "C:WINDOWSMicrosoft.NETFrameworkv3.0
Windows Workflow FoundationSQLENSqlPersistenceService_Schema.sql" SQLCMD -S .SqlExpress -d MyDB -i "C:WINDOWSMicrosoft.NETFrameworkv3.0
Windows Workflow FoundationSQLENSqlPersistenceService_Logic.sql" SQLCMD -S .SqlExpress -d MyDB -i "C:WINDOWSMicrosoft.NETFrameworkv3.0
Windows Workflow FoundationSQLENTracking_Schema.sql" SQLCMD -S .SqlExpress -d MyDB -i "C:WINDOWSMicrosoft.NETFrameworkv3.0
Windows Workflow FoundationSQLENTracking_Logic.sql"

Eddig egyszerű volt, de mi van akkor, ha saját tracking profile-t is akarunk használni? Erről annyit érdemes tudni, hogy a profil egy XML fájl, aminek a tartalmát az UpdateTrackingProfile tárolt eljárás segítségével kell egy táblába betöltenünk.

Általánosabban megfogalmazva a feladatot: hogyan tudunk egy olyan tárolt eljárást futtatni, aminek egyik bemeneti paramétere egy fájl teljes tartalma?

A megoldás első lépését a BULK INSERT T-SQL utasítás jelenti. Ennek megadhatunk egy fájl útvonalat, aminek a tartalmát be tudja tölteni egy táblába. Sajnos van néhány nyűgje:

  • Csak tábla típusú változót szeret, tehát nem elég egy DECLARE, csak CREATE TABLE jó neki.
  • A betöltendő fájl útvonalát nem lehet változóban megadni, oda kell írni aposztrófok közé.
  • Ha egy kulturáltan megformázott XML-t akarunk betölteni, akkor minden egyes sor külön rekordba kerül, ami persze nem jó, ha végül egyetlen cellában szeretnénk látni az eredményt.

Íme a megoldás:

    CREATE TABLE #temp( profileXml nvarchar(max) )


BULK INSERT #temp FROM '$(ProfilePath)' WITH ( ROWTERMINATOR = '<<<' -- dummy terminator, hogy az egész fájlt felolvassa )

Csinálunk tehát egy temp táblát, mert mindenképp tábla kell. Az egész fájl beolvasását úgy oldjuk meg, hogy olyan sor elválasztó karaktert adunk meg, ami biztosan nincs a fájlban. A kérdés már csak az, hogy mi a $(ProfilePath)?

Az SQLCMD egyik remek szolgáltatása, hogy lehet változókat megadni, amiket ő behelyettesít. A fenti aposztrófok közé például így varázsolhatunk értéket (a példa kedvéért elhagytam a többi paramétert):

    SQLCMD -v ProfilePath="profile.xml"

Ezzel megint csak gondunk lesz: a BULK INSERT panaszkodik, hogy nem teljes elérési utat adtunk meg. Kérdés: hogyan lehet egy cmd fájlban megtudni az aktuális mappa elérési útvonalát? Meglepő módon a cd parancs és a cd környezeti változó épp ezt adja vissza. Szerencsére az SQLCMD is tud környezeti változókat kezelni, így csak ennyit kell módosítanunk:

    SQLCMD -v ProfilePath="%cd%profile.xml"

Nem maradt más hátra, mint az UpdateTrackingProfile tárolt eljárás meghívása, amihez a már jól ismert EXEC utasítást használjuk. A profil XML-en kívül át kell neki adnunk egy TypeFullName, egy AssemblyName, és egy Version paramétert, melyeknél ugyanúgy járhatunk el, mint a fenti ProfilePath esetén. Ezek típusát és hosszát a tárolt eljárásból lehet kilesni.

Végül nekem a teljes SQL szkript így ez lett:

    -- Bemeneti paraméterek
    DECLARE @TypeFullName nvarchar(128)
    DECLARE @AssemblyName nvarchar(256)
    DECLARE @Version varchar(32)

    SET @TypeFullName = '$(TypeFullName)'
    SET @AssemblyName = '$(AssemblyName)'
    SET @Version = '$(Version)'

    -- Belső változók
    DECLARE @profileXml nvarchar(max)
    CREATE TABLE #temp( profileXml nvarchar(max) )

    -- Tracking profile betöltése fájlból temp táblába
    BULK INSERT #temp 
      FROM '$(ProfilePath)'
      WITH
      (
        ROWTERMINATOR = '<<<'  -- dummy terminator, hogy az egész fájlt felolvassa
      )

    -- Tracking profile XML kiolvasása temp táblából
    SELECT @profileXml = profileXml FROM #temp

    -- Tracking profile adatbázisba mentése
    EXEC dbo.UpdateTrackingProfile @TypeFullName, @AssemblyName, @Version, @profileXml

    -- Temp tábla törlése
    DROP TABLE #temp

És a cmd fájl, ami felépíti a teljes adatbázist és beimportálja a profilt (eltördeltem a hosszú sorokat):

    SQLCMD -S .SqlExpress -Q "CREATE DATABASE SignowDB"

    SQLCMD -S .SqlExpress -d MyDB -i "C:WINDOWSMicrosoft.NETFrameworkv3.0
Windows Workflow FoundationSQLENSqlPersistenceService_Schema.sql" SQLCMD -S .SqlExpress -d MyDB -i "C:WINDOWSMicrosoft.NETFrameworkv3.0
Windows Workflow FoundationSQLENSqlPersistenceService_Logic.sql" SQLCMD -S .SqlExpress -d MyDB -i "C:WINDOWSMicrosoft.NETFrameworkv3.0
Windows Workflow FoundationSQLENTracking_Schema.sql" SQLCMD -S .SqlExpress -d MyDB -i "C:WINDOWSMicrosoft.NETFrameworkv3.0
Windows Workflow FoundationSQLENTracking_Logic.sql" SQLCMD -S .SqlExpress -d MyDB -i "InsertTrackingProfile.sql" -v Version=1.0.0
-v TypeFullName="MyNamespace.MyWorkflow1"
-v AssemblyName="MyLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=443f6c5b661c8da2"
-v ProfilePath="%cd%profile1.xml" SQLCMD -S .SqlExpress -d MyDB -i "InsertTrackingProfile.sql" -v Version=1.0.0
-v TypeFullName="MyNamespace.MyWorkflow2"
-v AssemblyName="MyLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=443f6c5b661c8da2"
-v ProfilePath="%cd%profile2.xml"

A legjobb az egészben, hogy mindezt nem csak fejlesztés közben lehet használni, hanem ezt a szkriptet be lehet építeni a telepítő alkalmazásba is.

 

Technorati tags: , ,

Vélemény, hozzászólás?

Adatok megadása vagy bejelentkezés valamelyik ikonnal:

WordPress.com Logo

Hozzászólhat a WordPress.com felhasználói fiók használatával. Kilépés / Módosítás )

Twitter kép

Hozzászólhat a Twitter felhasználói fiók használatával. Kilépés / Módosítás )

Facebook kép

Hozzászólhat a Facebook felhasználói fiók használatával. Kilépés / Módosítás )

Google+ kép

Hozzászólhat a Google+ felhasználói fiók használatával. Kilépés / Módosítás )

Kapcsolódás: %s