Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Code First Migrations är det rekommenderade sättet att utveckla programmets databasschema om du använder arbetsflödet Code First. Migreringar tillhandahåller en uppsättning verktyg som tillåter:
- Skapa en första databas som fungerar med din EF-modell
- Generera migreringar för att hålla reda på de ändringar du gör i DIN EF-modell
- Håll databasen uppdaterad med dessa ändringar
Följande genomgång ger en översikt över Code First Migrations i Entity Framework. Du kan antingen slutföra hela genomgången eller gå vidare till det ämne som du är intresserad av. Följande avsnitt beskrivs:
Skapa en inledande modell och databas
Innan vi börjar använda migreringar behöver vi ett projekt och en Code First-modell att arbeta med. För den här genomgången ska vi använda den kanoniska blogg- och postmodellen.
- Skapa ett nytt MigreringsDemo-konsolprogram
- Lägg till den senaste versionen av EntityFramework NuGet-paketet i projektet
- Verktyg –> Bibliotekspakethanteraren –> Package Manager-konsolen
- Kör kommandot Install-Package EntityFramework
- Lägg till en Model.cs fil med koden som visas nedan. Den här koden definierar en enskild bloggklass som utgör vår domänmodell och en BlogContext-klass som är vår EF Code First-kontext
using System.Data.Entity;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity.Infrastructure;
namespace MigrationsDemo
{
public class BlogContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
}
}
- Nu när vi har en modell är det dags att använda den för att utföra dataåtkomst. Uppdatera Program.cs-filen med koden som visas nedan.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MigrationsDemo
{
class Program
{
static void Main(string[] args)
{
using (var db = new BlogContext())
{
db.Blogs.Add(new Blog { Name = "Another Blog " });
db.SaveChanges();
foreach (var blog in db.Blogs)
{
Console.WriteLine(blog.Name);
}
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
}
Kör programmet så ser du att en MigrationsCodeDemo.BlogContext-databas har skapats åt dig.
Aktivera migreringar
Det är dags att göra några fler ändringar i vår modell.
- Nu ska vi introducera en URL-egenskap till klassen Blogg.
public string Url { get; set; }
Om du skulle köra programmet igen skulle du få en InvalidOperationException som anger att modellen som stöder "BlogContext"-kontexten har ändrats sedan databasen skapades. Överväg att använda Code First Migrations för att uppdatera databasen (http://go.microsoft.com/fwlink/?LinkId=238269).
Som undantaget antyder är det dags att börja använda Code First Migrations. Det första steget är att aktivera migreringar för vår kontext.
Kör kommandot Enable-Migrations i Package Manager Console
Det här kommandot har lagt till en migreringsmapp i vårt projekt. Den här nya mappen innehåller två filer:
Konfigurationsklassen. Med den här klassen kan du konfigurera hur migreringar fungerar för din kontext. För den här genomgången använder vi bara standardkonfigurationen. Eftersom det bara finns en enda Code First-kontext i projektet har Enable-Migrations automatiskt fyllt i den kontexttyp som den här konfigurationen gäller för.
En InitialCreate-migrering. Den här migreringen genererades eftersom vi redan hade Code First som skapade en databas åt oss, innan vi aktiverade migreringar. Koden i denna skaffolderade migrering representerar de objekt som redan har skapats i databasen. I vårt fall är det tabellen Blogg med kolumnerna BlogId och Name . Filnamnet innehåller en tidsstämpel som hjälper dig med beställning. Om databasen inte redan hade skapats skulle den här InitialCreate-migreringen inte ha lagts till i projektet. I stället skulle första gången vi anropar Add-Migration koden för att skapa dessa tabeller kodas till en ny migrering.
Flera modeller som riktar sig mot samma databas
När du använder versioner före EF6 kan endast en Code First-modell användas för att generera/hantera schemat för en databas. Detta är resultatet av en enda __MigrationsHistory tabell per databas utan något sätt att identifiera vilka poster som tillhör vilken modell.
Från och med EF6 innehåller klassen Configuration en ContextKey-egenskap . Detta fungerar som en unik identifierare för varje Code First-modell. En motsvarande kolumn i tabellen __MigrationsHistory tillåter poster från flera modeller att dela tabellen. Som standard är den här egenskapen inställd på det fullständigt kvalificerade namnet på kontexten.
Generera och köra migreringar
Code First Migrations har två primära kommandon som du kommer att bekanta dig med.
- Add-Migration kommer att skapa nästa migrering baserat på ändringar som du har gjort i din modell sedan den senaste migreringen skapades
- Update-Database tillämpar eventuella väntande migreringar på databasen
Vi måste skapa en migrering för att ta hand om den nya URL-egenskapen som vi har lagt till. Med kommandot Add-Migration kan vi ge migreringarna ett namn. Vi anropar bara addblogurl.
- Kör kommandot Add-Migration AddBlogUrl i Package Manager Console
- I mappen Migrering har vi nu en ny AddBlogUrl-migrering . Migreringsfilnamnet är förbestämt med en tidsstämpel för att hjälpa till med beställning
namespace MigrationsDemo.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class AddBlogUrl : DbMigration
{
public override void Up()
{
AddColumn("dbo.Blogs", "Url", c => c.String());
}
public override void Down()
{
DropColumn("dbo.Blogs", "Url");
}
}
}
Nu kan vi redigera eller lägga till den här migreringen, men allt ser ganska bra ut. Nu ska vi använda Update-Database för att tillämpa den här migreringen på databasen.
- Kör kommandot Update-Database i Package Manager Console
- Code First Migrations jämför migreringarna i mappen Migreringar med de som har tillämpats på databasen. Den ser att Migreringen AddBlogUrl måste tillämpas och sedan köra den.
Databasen MigrationsDemo.BlogContext har nu uppdaterats för att inkludera url-kolumnen i tabellen Bloggar .
Anpassa migreringar
Hittills har vi genererat och kört en migrering utan att göra några ändringar. Nu ska vi titta på hur du redigerar koden som genereras som standard.
- Det är dags att göra några fler ändringar i vår modell, nu ska vi lägga till en ny klassificeringsegenskap i bloggklassen
public int Rating { get; set; }
- Nu ska vi också lägga till en ny Post-klass
public class Post
{
public int PostId { get; set; }
[MaxLength(200)]
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
- Vi lägger också till en inläggssamling i klassen Blogg för att bilda den andra änden av relationen mellan Blogg och Inlägg
public virtual List<Post> Posts { get; set; }
Vi använder kommandot Add-Migration för att låta Code First Migrations skapa sin bästa gissning vid migreringen åt oss. Vi ska kalla migreringen AddPostClass.
- Kör kommandot Add-Migration AddPostClass i Package Manager Console.
Code First Migrations gjorde ett ganska bra jobb med att skapa dessa ändringar, men det finns några saker som vi kanske vill ändra:
- Först ska vi lägga till ett unikt index i kolumnen Posts.Title (Lägg till på rad 22 och 29 i koden nedan).
- Vi lägger också till kolumnen Blogs.Rating som inte kan ogiltigas. Om det finns några befintliga data i tabellen tilldelas den CLR-standardvärdet för datatypen för ny kolumn (Klassificering är heltal, så det skulle vara 0). Men vi vill ange ett standardvärde på 3 så att befintliga rader i tabellen Bloggar börjar med ett anständigt omdöme. (Du kan se standardvärdet som anges på rad 24 i koden nedan)
namespace MigrationsDemo.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class AddPostClass : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.Posts",
c => new
{
PostId = c.Int(nullable: false, identity: true),
Title = c.String(maxLength: 200),
Content = c.String(),
BlogId = c.Int(nullable: false),
})
.PrimaryKey(t => t.PostId)
.ForeignKey("dbo.Blogs", t => t.BlogId, cascadeDelete: true)
.Index(t => t.BlogId)
.Index(p => p.Title, unique: true);
AddColumn("dbo.Blogs", "Rating", c => c.Int(nullable: false, defaultValue: 3));
}
public override void Down()
{
DropIndex("dbo.Posts", new[] { "Title" });
DropIndex("dbo.Posts", new[] { "BlogId" });
DropForeignKey("dbo.Posts", "BlogId", "dbo.Blogs");
DropColumn("dbo.Blogs", "Rating");
DropTable("dbo.Posts");
}
}
}
Vår redigerade migrering är klar, så låt oss använda Update-Database för att uppdatera databasen till aktuellt läge. Den här gången ska vi ange flaggan –Verbose så att du kan se SQL:en att Code First Migrations körs.
- Kör kommandot Update-Database –Verbose i Package Manager Console.
Data motion/anpassad SQL
Hittills har vi tittat på migreringsåtgärder som inte ändrar eller flyttar några data. Nu ska vi titta på något som behöver flytta runt lite data. Det finns inget internt stöd för datarörelse ännu, men vi kan köra några godtyckliga SQL-kommandon när som helst i skriptet.
- Nu ska vi lägga till en Post.Abstract-egenskap i vår modell. Senare kommer vi att förfylla Sammanfattning för existerande inlägg genom att använda text från början av kolumnen Innehåll.
public string Abstract { get; set; }
Vi använder kommandot Add-Migration för att låta Code First Migrations skapa sin bästa gissning vid migreringen åt oss.
- Kör kommandot Add-Migration AddPostAbstract i Package Manager Console.
- Den genererade migreringen tar hand om schemaändringarna, men vi vill också fylla i kolumnen Abstrakt i förväg med hjälp av de första 100 tecknen i innehållet för varje inlägg. Vi kan göra detta genom att släppa ned till SQL och köra en UPDATE-instruktion när kolumnen har lagts till. (Lägg till på rad 12 i koden nedan)
namespace MigrationsDemo.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class AddPostAbstract : DbMigration
{
public override void Up()
{
AddColumn("dbo.Posts", "Abstract", c => c.String());
Sql("UPDATE dbo.Posts SET Abstract = LEFT(Content, 100) WHERE Abstract IS NULL");
}
public override void Down()
{
DropColumn("dbo.Posts", "Abstract");
}
}
}
Vår redigerade migrering ser bra ut, så vi använder Update-Database för att uppdatera databasen till den senaste versionen. Vi anger flaggan –Verbose så att vi kan se att SQL körs mot databasen.
- Kör kommandot Update-Database –Verbose i Package Manager Console.
Migrera till en specifik version (inklusive nedgradering)
Hittills har vi alltid uppgraderat till den senaste migreringen, men det kan finnas tillfällen då du vill uppgradera/nedgradera till en specifik migrering.
Anta att vi vill migrera databasen till det tillstånd den befann sig i efter att ha kört vår AddBlogUrl-migrering . Vi kan använda växeln –TargetMigration för att nedgradera till den här migreringen.
- Kör kommandot Update-Database –TargetMigration: AddBlogUrl i Package Manager Console.
Det här kommandot kör down-skriptet för migreringarna AddBlogAbstract och AddPostClass .
Om du vill återställa hela vägen tillbaka till en tom databas kan du använda kommandot Update-Database –TargetMigration: $InitialDatabase .
Hämta ett SQL-skript
Om en annan utvecklare vill ha dessa ändringar på sin dator kan de bara synkroniseras när vi har kontrollerat våra ändringar i källkontrollen. När de har våra nya migreringar kan de bara köra kommandot Update-Database för att tillämpa ändringarna lokalt. Men om vi vill push-överföra dessa ändringar till en testserver, och så småningom produktion, vill vi förmodligen ha ett SQL-skript som vi kan lämna över till vår DBA.
- Kör kommandot Update-Database men den här gången anger du flaggan –Script så att ändringar skrivs till ett skript i stället för att tillämpas. Vi kommer också att specificera en källa och ett mål för migrationen för att generera skriptet. Vi vill att ett skript ska gå från en tom databas ($InitialDatabase) till den senaste versionen (migrering AddPostAbstract). Om du inte anger en målmigrering använder migreringar den senaste migreringen som mål. Om du inte anger någon källmigrering använder migreringar databasens aktuella tillstånd.
- Kör kommandot Update-Database -Script -SourceMigration: $InitialDatabase -TargetMigration: AddPostAbstract i Package Manager Console
Code First Migrations kör migreringspipelinen, men i stället för att faktiskt tillämpa ändringarna skrivs de ut till en .sql fil åt dig. När skriptet har genererats öppnas det åt dig i Visual Studio, som är redo att visas eller sparas.
Generera Idempotent-skript
Från och med EF6, om du anger – SourceMigration $InitialDatabase blir det genererade skriptet "idempotent". Idempotent-skript kan uppgradera en databas för närvarande i valfri version till den senaste versionen (eller den angivna versionen om du använder – TargetMigration). Det genererade skriptet innehåller logik för att kontrollera tabellen __MigrationsHistory och tillämpa endast ändringar som inte har tillämpats tidigare.
Uppgradera automatiskt vid programstart (MigrateDatabaseToLatestVersion Initializer)
Om du distribuerar ditt program kanske du vill att det ska uppgradera databasen automatiskt (genom att tillämpa väntande migreringar) när programmet startas. Du kan göra detta genom att registrera databasinitieraren MigrateDatabaseToLatestVersion . En databasinitierare innehåller helt enkelt viss logik som används för att kontrollera att databasen är korrekt konfigurerad. Den här logiken körs första gången kontexten används i programprocessen (AppDomain).
Vi kan uppdatera Program.cs-filen , som visas nedan, för att ange initieraren MigrateDatabaseToLatestVersion för BlogContext innan vi använder kontexten (rad 14). Observera att du också måste lägga till en using-instruktion för namnområdet System.Data.Entity (rad 5).
När vi skapar en instans av den här initiatorn måste vi ange kontexttypen (BlogContext) och migreringskonfigurationen (konfiguration) – migreringskonfigurationen är den klass som lades till i mappen Migreringar när vi aktiverade migreringar.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using MigrationsDemo.Migrations;
namespace MigrationsDemo
{
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<BlogContext, Configuration>());
using (var db = new BlogContext())
{
db.Blogs.Add(new Blog { Name = "Another Blog " });
db.SaveChanges();
foreach (var blog in db.Blogs)
{
Console.WriteLine(blog.Name);
}
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
}
Nu när vårt program körs kontrollerar det först om databasen den riktar sig till är up-to-date och tillämpar eventuella väntande migreringar om det inte är det.