Att underhålla en databas (del 2 – Entity Framework Migrations)

No Gravatar

Denna blogpost är en fortsättning på Att underhålla en databas (del 1).

Microsoft släppte i våras Entity Framework Migrations, vilket är ett Migrations-verktyg för oss som sitter i .Net. Idén bakom verktyget är inte nytt, då det t.ex kommer med ramverket ruby on rails där det kallas Active Records Migrations, och det har även funnits tredjeparts ramverk till C# så som DotNetMigrations. Så hur fungerar EF Migrations och på vilket sätt är det det bästa migrations-verktyget som jag än så länge har sett (oberoende av plattform)?

Ett migrations-verktyg bygger på principen av förändringsskript som jag beskrev i min föregående blogpost. Migrations bygger vidare på den idén genom att definiera en struktur för skripten, och automatiserar hanteringen av dem.

I EF Migrations så är strukturen så simpel som en mapp med .cs filer, där varje fil representerar en migration. En migration består av två förändringsskript; Ett “Up”-skript för hur en förändring appliceras, samt ett “Down”-skript för hur samma förändring reverseras. Varje migration får dessutom en timestamp prefixat på sitt filnamn, så att det finns en enkel och tydlig ordning mellan de olika skripten.

För att hålla reda på i vilket tillstånd din databas befinner sig i så skapar EF migrations en tabell i din databas som heter __MigrationHistory som innehåller information om vilka migrations som är applicerade på databasen, så att när du ber om att uppdatera databasen till en viss version, så vet den vilka migrations den behöver applicera alternativt reversera. Man kan be EF Migrations att antingen applicera förändringarna direkt, eller att få ut ett SQL skript som man kan ge till en DBA att köra vid produktionssättning och uppdatering.

Det är hela idén. Så simpelt är det. Men det är även det som gör det så vackert och smidigt att arbeta med.

Vill man skapa en ny migration så öppnar man Package Manager Console och skriver “Add-Migration” följt av namnet på sin migration (i exemplet nedan AddTableEmployees) och man möts då av en tom fil:

<span style="color: blue">using </span>System.Data.Entity.Migrations;

<span style="color: blue">public partial class </span><span style="color: #2b91af">AddTableEmployees </span>: <span style="color: #2b91af">DbMigration
</span>{
    <span style="color: blue">public override void </span>Up()
    {

    }

    <span style="color: blue">public override void </span>Down()
    {

    }
}

Det som är verkligt smidigt med EF Migrations, och som får det att bli mycket mer attraktivt än de andra migrationsramverken som jag har använt, är hur man kan skriva sina migrations helt i C#:

<span style="color: blue">using </span>System.Data.Entity.Migrations;

<span style="color: blue">public partial class </span><span style="color: #2b91af">AddTableEmployees </span>: <span style="color: #2b91af">DbMigration
</span>{
    <span style="color: blue">public override void </span>Up()
    {
        CreateTable(
            <span style="color: #a31515">"Employees"</span>,
            cb =&gt; <span style="color: blue">new
            </span>{
                EmployeeId = cb.Long(
                    nullable: <span style="color: blue">false</span>,
                    identity: <span style="color: blue">true</span>),
                FirstName = cb.String(
                    nullable: <span style="color: blue">true</span>,
                    unicode: <span style="color: blue">true</span>,
                    maxLength: 150)
            });
    }

    <span style="color: blue">public override void </span>Down()
    {
        DropTable(<span style="color: #a31515">"Employees"</span>);
    }
}

Men man kan samtidigt lika enkelt skriva vanlig SQL:

<span style="color: blue">public partial class </span><span style="color: #2b91af">ExampleSqlMigration </span>: <span style="color: #2b91af">DbMigration
</span>{
    <span style="color: blue">public override void </span>Up()
    {
        Sql(<span style="color: #a31515">@"UPDATE Employees 
              SET FirstName = ''
              WHERE FirstName IS NULL"</span>);
    }

    <span style="color: blue">public override void </span>Down()
    {
        <span style="color: green">// Reversal of migration not necessary.
    </span>}
}

För att applicera migrations mot sin lokala databas så skriver man “Update-Database” i Package Manager Console. För att reversera så kan man använda “-TargetMigration:” flaggan och namnge den migration som man vill gå till.

Jag har medvetet utelämnat det som kallas för “Code first migrations” från Entity Framework, för jag tycker pesonligen inte att det är det som gör migrations fantastiskt, även om det är mycket kraftfullt. Vem vet, det kanske blir en del 3 i framtiden som handlar om just detta.

Jag kommer prata mer om Entity Framework Migrations på nforum den 19:e september 2012, så kom gärna och lyssna!

Att underhålla en databas (del 1)

No Gravatar

Om du utvecklar en applikation som använder sig av en SQL databas så är chansen stor, om inte oundviklig, att du måste underhålla databasschemat under utveckling såväl som både schema och data när applikationen väl är satt i produktion. Jag tänkte snabbt gå igenom de saker som jag personligen ser som mest fundamentala då det gäller databashantering ur en programmerares synvinkel.

Underhåll

Att kunna bygga och underhålla en databas, att kunna hantera SQL, bör vara ett verktyg som finns i varje utvecklares verktygslåda. Men att kunna använda ett verktyg och att kunna använda det på ett ansvarfullt sätt är två olika saker. Majoriteten av all utvecklare är ansvarsfulla nog att veta att de bör versionshantera sin kod. Men jag vill påstå att det är lika viktigt att du har din databas i ditt versionerings system. Och detta bör du ha från dag ett. Jag har hört många som säger att de väntar med det tills dess systemet sätts i produktion, men detta är bara att vara onödigt lat.

Representation

Det finns två stycken grundläggande sätt att representera sin databas i kod/script-form. Det mest grundläggande, men enligt min pesonliga åsikt dock ej att föredra, är en statisk representation av din databas. Detta kan t.ex. vara en upsättning av SQL CREATE och ALTER script som beskriver hur du sätter upp databasen från scratch. Det andra sättet, och det jag rekommenderar, är att använda sig av “förändrings”-script som beskriver databasen genom steg-för-steg modifikationer.

Som exempel säg att vi har en databas med en tabell Employees som skapades genom:

<span class="kwrd">CREATE</span> <span class="kwrd">TABLE</span> Employees 
( 
    EmployeeId BIGINT <span class="kwrd">IDENTITY</span>(1,1) <span class="kwrd">NOT</span> <span class="kwrd">NULL</span>, 
    Firstname NVARCHAR(50) <span class="kwrd">NOT</span> <span class="kwrd">NULL</span> 
)

Vi vill nu lägga till efternamn som en kolumn. Om du har en statisk representation skulle du ändra i den redan existerande filen till:

<span class="kwrd">CREATE</span> <span class="kwrd">TABLE</span> Employees 
( 
    EmployeeId BIGINT <span class="kwrd">IDENTITY</span>(1,1) <span class="kwrd">NOT</span> <span class="kwrd">NULL</span>, 
    Firstname NVARCHAR(50) <span class="kwrd">NOT</span> <span class="kwrd">NULL</span>, 
    Lastname NVARCHAR(50) <span class="kwrd">NOT</span> <span class="kwrd">NULL</span> 
)

Men om du använder dig av förändringsskript så skulle du skapa en ny fil där det står:

<span class="kwrd">ALTER</span> <span class="kwrd">TABLE</span> Employees 
<span class="kwrd">ADD</span> <span class="kwrd">COLUMN</span> Lastname NVARCHAR(50) <span class="kwrd">NOT</span> <span class="kwrd">NULL</span> 

Personligen så tycker jag att den största fördelen med förändringsskript är när man skall uppdatera en eller flera produktionsdatabaser, med en enkla anledningen att det bara är att köra skripten.

Detta förutsätter dock såklart att man vet vilka skript som redan körts på respektive databas. Mitt rekommenderade sätt att hantera det är att arbeta med Migrations, vilket jag snart kommer blogga om i nästa del här på Squeedbloggen.

Dessa förändringsskript skall behandlas som vilken annan kod som hällst, vilket betyder att den skall kodgranskas och testas (föreslagsvis så kan man ha ett automatisk test som applicerar alla förändringsskripten i ordning, mot den databas som man kör integrationstester emot).