Kód első migrálása

A Code First Migrations a javasolt módszer az alkalmazás adatbázisséma továbbfejlesztésére, ha a Code First munkafolyamatot használja. A migrálások olyan eszközök készletét biztosítják, amelyek lehetővé teszik az alábbiakat:

  1. Az EF-modellel működő kezdeti adatbázis létrehozása
  2. Migrálások létrehozása az EF-modell módosításainak nyomon követéséhez
  3. Az adatbázis naprakészen tartása a módosításokkal

Az alábbi útmutató áttekintést nyújt a Code First Migrations in Entity Frameworkről. Elvégezheti a teljes bemutatót, vagy átugorhat az ön által érdekes témára. Az alábbi témaköröket ismertetik:

Kezdeti modell és adatbázis létrehozása

A migrálások használatba vétele előtt egy projektre és egy Code First modellre van szükség a használathoz. Ehhez az útmutatóhoz a canonical Blog and Post modellt fogjuk használni.

  • Új MigrationsDemo-konzolalkalmazás létrehozása
  • Adja hozzá az EntityFramework NuGet-csomag legújabb verzióját a projekthez
    • Eszközök –> Könyvtárcsomag-kezelő –> Csomagkezelő konzol
    • Az Install-Package EntityFramework parancs futtatása
  • Adjon hozzá egy Model.cs fájlt az alábbi kóddal. Ez a kód egyetlen blogosztályt határoz meg, amely a tartománymodellt és egy BlogContext osztályt határoz meg, amely az EF Code First-környezetünk.
    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; }
        }
    }
  • Most, hogy rendelkezünk egy modellel, itt az ideje, hogy adathozzáférést hajtsunk végre. Frissítse a Program.cs fájlt az alábbi kóddal.
    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();
            }
        }
    }
  • Futtassa az alkalmazást, és látni fogja, hogy egy MigrationsCodeDemo.BlogContext adatbázis jön létre.

    Database LocalDB

Áttelepítések engedélyezése

Itt az ideje, hogy további módosításokat hajtsunk végre a modellen.

  • Lássunk be egy URL-tulajdonságot a Blog osztályba.
    public string Url { get; set; }

Ha ismét futtatni szeretné az alkalmazást, egy InvalidOperationException hibaüzenetet kap, amely szerint a "BlogContext" környezet hátterében lévő modell megváltozott az adatbázis létrehozása óta. Fontolja meg a Code First Migrations használatát az adatbázis (http://go.microsoft.com/fwlink/?LinkId=238269) frissítéséhez.

Ahogy a kivétel is sugallja, ideje elkezdeni a Code First Migrations használatát. Az első lépés az áttelepítések engedélyezése a környezetünkben.

  • Az Enable-Migrations parancs futtatása a Package Manager konzolon

    Ez a parancs hozzáadta a migrálási mappát a projekthez. Ez az új mappa két fájlt tartalmaz:

  • A Konfiguráció osztály. Ez az osztály lehetővé teszi a migrálások viselkedésének konfigurálását a környezethez. Ehhez az útmutatóhoz csak az alapértelmezett konfigurációt fogjuk használni. Mivel a projektben csak egyetlen Code First környezet található, Enable-Migrations automatikusan kitöltötte azt a környezettípust, amelyre ez a konfiguráció vonatkozik.

  • InitialCreate-migrálás. Ez az áttelepítés azért jött létre, mert a Code First már létrehozott nekünk egy adatbázist, mielőtt engedélyeztük volna az áttelepítést. Az állványos migrálásban szereplő kód az adatbázisban már létrehozott objektumokat jelöli. Esetünkben ez a Blog tábla egy BlogId és Név oszlopokkal. A fájlnév tartalmaz egy időbélyeget a rendeléshez. Ha az adatbázis még nem lett volna létrehozva, ez az InitialCreate migrálás nem lett volna hozzáadva a projekthez. Ehelyett, amikor először hívjuk meg az Add-Migration parancsot, a táblák létrehozásához szükséges kód egy új migrációba kerül előkészítésre.

Több modell, amely ugyanazt az adatbázist célozza

Ha az EF6 előtti verziókat használja, az adatbázis sémájának létrehozásához/kezeléséhez csak egy Első kódmodell használható. Ez adatbázisonként egyetlen __MigrationsHistory tábla eredménye, amely nem tudja azonosítani, hogy mely bejegyzések melyik modellhez tartoznak.

Az EF6-tól kezdve a Konfiguráció osztály tartalmaz egy ContextKey tulajdonságot. Ez egyedi azonosítóként szolgál az egyes Code First-modellekhez. A __MigrationsHistory tábla megfelelő oszlopával több modell bejegyzései oszthatják meg a táblát. Alapértelmezés szerint ez a tulajdonság az Ön környezetének teljes, minősített neveként van beállítva.

Migrálások létrehozása és futtatása

A Code First Migrations két elsődleges parancsot tartalmaz, amelyeket ismerni fog.

  • A bővítménymigrálás a következő migrálást fogja összehozni a modell legutóbbi létrehozása óta végrehajtott módosítások alapján
  • Az Update-Database minden függőben lévő migrálást alkalmaz az adatbázisra

A migrálás keretrendszerét ki kell dolgoznunk, hogy kezeljük az új URL tulajdonságot, amelyet hozzáadtunk. Az Add-Migration paranccsal nevet adhatunk ezeknek az áttelepítéseknek, hívjuk meg az AddBlogUrl nevet.

  • Futtassa a Add-Migration AddBlogUrl parancsot a Package Manager-konzolon
  • A Migrations mappában most már van egy új AddBlogUrl migrálás. A migrálási fájlnév előre lett ellátva egy időbélyeggel, amely segít a rendezésben.
    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");
            }
        }
    }

Most már módosíthatjuk vagy hozzáadhatjuk ezt a migrációt, de minden rendben van. Az Update-Database használatával alkalmazzuk ezt az áttelepítést az adatbázisra.

  • Az Update-Database parancs futtatása a Package Manager konzolon
  • A Code First Migrations összehasonlítja a Migrálások mappában lévő áttelepítéseket az adatbázisra alkalmazottakkal. Látható, hogy az AddBlogUrl migrációt kell alkalmazni és futtatni.

A MigrationsDemo.BlogContext adatbázis frissült, hogy az URL-oszlop szerepeljen a Blogok táblában.

Migrálások testreszabása

Eddig módosítás nélkül hoztunk létre és futtattunk migrálást. Most nézzük meg az alapértelmezés szerint létrehozott kód szerkesztését.

  • Itt az ideje, hogy további módosításokat hajtsunk végre a modellen, adjunk hozzá egy új Minősítés tulajdonságot a Blog osztályhoz
    public int Rating { get; set; }
  • Adjunk hozzá egy új Post osztályt is
    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; }
    }
  • Egy Bejegyzésgyűjteményt is hozzáadunk a Blog osztályhoz, hogy a Blog és a Post közötti kapcsolat másik végét képezzük
    public virtual List<Post> Posts { get; set; }

Az Add-Migration parancsot használjuk, hogy a Code First Migrations előkészítse számunkra a migráció legjobb változatát. Ezt a migrálást AddPostClass-nak fogjuk hívni.

  • Futtassa a Add-Migration AddPostClass parancsot a Package Manager konzolon.

A Code First Migrations nagyon jó munkát végzett ezeknek a módosításoknak az állványzatán, de lehet, hogy módosítani szeretnénk néhány dolgot:

  1. Először is adjunk hozzá egy egyedi indexet a Posts.Title oszlophoz (hozzáadás a 22. és 29. sorban az alábbi kódban).
  2. Egy nem null értékű Blogs.Rating oszlopot is hozzáadunk. Ha a táblában vannak meglévő adatok, akkor az új oszlop adattípusának CLR-alapértelmezése lesz hozzárendelve (a minősítés egész szám, tehát 0 lesz). De meg szeretnénk adni egy alapértelmezett 3 értéket, hogy a Blogok tábla meglévő sorai tisztességes értékeléssel kezdődjenek. (Az alapértelmezett érték az alábbi kód 24. sorában látható)
    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");
            }
        }
    }

A szerkesztett migrálás készen áll az indulásra, ezért az Update-Database használatával tegyük naprakésszé az adatbázist. Ezúttal adja meg a –Verbose kapcsolót, hogy láthassa a Code First Migrations által futtatott SQL-parancsokat.

  • Futtassa az Update-Database –Verbose parancsot a Package Manager Console-ban.

Data Motion / Egyéni SQL

Eddig olyan migrálási műveleteket vizsgáltunk meg, amelyek nem módosítanak vagy helyeznek át adatokat, most pedig nézzünk meg valamit, amihez át kell helyeznie néhány adatot. Az adatmozduláshoz még nincs natív támogatás, de tetszőleges SQL-parancsokat futtathatunk a szkriptünk bármely pontján.

  • Adjunk hozzá egy Post.Abstract tulajdonságot a modellhez. Később előre kitöltjük az Absztraktot a meglévő bejegyzésekhez a Tartalom oszlop elején lévő szöveg használatával.
    public string Abstract { get; set; }

A Add-Migration paranccsal elindítjuk, hogy a Code First Migrations elkészítse saját legjobb elképzelése alapján a migrációs vázlatot számunkra.

  • Futtassa a Add-Migration AddPostAbstract parancsot a Package Manager-konzolon.
  • A létrehozott migrálás gondoskodik a séma módosításairól, de az absztrakt oszlopot is előre fel szeretnénk tölteni az egyes bejegyzések első 100 karakternyi tartalommal. Ezt úgy teheti meg, hogy leugrunk az SQL-hez, és futtatunk egy UPDATE utasítást az oszlop hozzáadása után. (Hozzáadás a 12. sorban az alábbi kódban)
    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");
            }
        }
    }

A módosított migráció jól néz ki, ezért használjuk az Update-Database parancsot az adatbázis naprakésszé tételéhez. Meg fogjuk adni a –Részletes jelzőt, hogy láthassuk, hogyan fut az SQL az adatbázissal szemben.

  • Futtassa az Update-Database –Verbose parancsot a Package Manager Konzolon.

Migrálás egy adott verzióra (beleértve a leminősítést is)

Eddig mindig a legújabb migrálásra frissítettünk, de előfordulhatnak olyan esetek, amikor egy adott migrálásra szeretne frissíteni vagy visszaminősíteni.

Tegyük fel, hogy az AddBlogUrl migrálás futtatása után az adatbázist arra az állapotra szeretnénk migrálni, amelyben volt. A –TargetMigration kapcsolóval visszaminősíthetjük ezt a migrálást.

  • Futtassa a Update-Database –TargetMigration: AddBlogUrl parancsot a Package Manager-konzolon.

Ez a parancs lefuttatja az AddBlogAbstract és az AddPostClass migráláshoz tartozó Down szkriptet.

Ha teljesen vissza szeretne gördülni egy üres adatbázisba, használhatja a Update-Database –TargetMigration: $InitialDatabase parancsot.

SQL-szkript beszerzése

Ha egy másik fejlesztő szeretné ezeket a módosításokat a gépükön, egyszerűen szinkronizálhatja őket, miután ellenőriztük a módosításokat a forráskövetésben. Az új migrálások után egyszerűen futtathatják a Update-Database parancsot a módosítások helyi alkalmazásához. Ha azonban ezeket a módosításokat egy tesztkiszolgálóra szeretnénk leküldni, és végül éles környezetben szeretnénk elvégezni, valószínűleg egy SQL-szkriptet szeretnénk, amelyet átadhatunk a DBA-nak.

  • Futtassa az Update-Database parancsot, de ezúttal adja meg a –Script jelölőt, hogy a módosítások a szkriptbe legyenek írva ahelyett, hogy alkalmazva lettek. Meghatározunk egy forrást és egy célt is a migrációs szkript létrehozásához. Azt szeretnénk, ha egy szkript egy üres adatbázisból ($InitialDatabase) a legújabb verzióra (az AddPostAbstract áttelepítése) haladna. Ha nem ad meg célmigrációt, a migrációk a legújabb migrációt fogják célként használni. Ha nem ad meg forrásmigrálást, az áttelepítések az adatbázis aktuális állapotát fogják használni.
  • Futtassa a Update-Database -Script -SourceMigration: $InitialDatabase -TargetMigration: AddPostAbstract parancsot a Package Manager konzolon

A Code First Migrations futtatja az áttelepítési folyamatot, de a módosítások tényleges alkalmazása helyett kiírja őket egy .sql fájlba. A szkript létrehozása után megnyílik a Visual Studióban, és készen áll a megtekintésre vagy mentésre.

Idempotens szkriptek létrehozása

Az EF6-tól kezdve, ha megadja a –SourceMigration $InitialDatabase , akkor a létrehozott szkript "idempotens" lesz. Az idempotens scriptek bármely verzióját frissíthetik az adatbázisnak a legújabb verzióra (vagy a megadott verzióra, ha a –TargetMigration használatban van). A létrehozott szkript logikával ellenőrzi a __MigrationsHistory táblát, és csak a korábban nem alkalmazott módosításokat alkalmazza.

Automatikus frissítés alkalmazásindításkor (MigrateDatabaseToLatestVersion Initializer)

Ha telepíti az alkalmazást, érdemes lehet automatikusan frissítenie az adatbázist (a függőben lévő áttelepítések alkalmazásával), amikor az alkalmazás elindul. Ehhez regisztrálja a MigrateDatabaseToLatestVersion adatbázis-inicializálót. Az adatbázis-inicializáló egyszerűen tartalmaz néhány logikát, amellyel meggyőződhet arról, hogy az adatbázis megfelelően van beállítva. Ez a logika akkor fut, amikor először használja a környezetet az alkalmazásfolyamatban (AppDomain).

Az alábbi módon frissíthetjük a Program.cs fájlt a BlogContext MigrateDatabaseToLatestVersion inicializálójának beállításához a környezet használata előtt (14. sor). Vegye figyelembe, hogy a System.Data.Entity névtérhez (5. sor) is hozzá kell adnia egy felhasználói utasítást.

Az inicializáló példányának létrehozásakor meg kell adnia a környezet típusát (BlogContext) és a migrálási konfigurációt (Konfiguráció) – a migrálási konfiguráció az az osztály, amelyet a migrálás engedélyezésekor hozzáadtunk a Migrálások mappához.

    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();
            }
        }
    }

Most, amikor az alkalmazás fut, először ellenőrzi, hogy a célzott adatbázis naprakész-e, és alkalmazza a függőben lévő migrációkat, ha nem.