文章出處

Setting up Code First Migrations for Model Changes--為模型更改做數據庫遷移。

1.打開資源管理器,在App_Data文件夾下,找到movies.mdf數據庫文件,如果沒有看到點擊顯示所有文件。

2.刪掉movies.mdf數據庫文件,并編譯項目。確保沒有報錯。

3.找到工具菜單欄下面的NuGet程序包管理器---程序包管理器控制臺,如圖所示:

4,在程序包管理器控制臺中,輸入:Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext    

(注意: MvcMovie.Models.MovieDBContext    項目名.Models.項目數據上下文)

按enter鍵之后,可以看到:

5,數據庫遷移之后,VS中自動為我們生成了一個Migrations文件夾,里面有一個Configuration.cs文件

 

6.打開Configuration.cs文件,引用命名空間:

using MvcMovie.Models;

然后在Seed方法中寫上:

 

 1 protected override void Seed(MvcMovie.Models.MovieDBContext context)
 2 {
 3     context.Movies.AddOrUpdate( i => i.Title,
 4         new Movie
 5         {
 6             Title = "When Harry Met Sally",
 7             ReleaseDate = DateTime.Parse("1989-1-11"),
 8             Genre = "Romantic Comedy",
 9             Price = 7.99M
10         },
11 
12          new Movie
13          {
14              Title = "Ghostbusters ",
15              ReleaseDate = DateTime.Parse("1984-3-13"),
16              Genre = "Comedy",
17              Price = 8.99M
18          },
19 
20          new Movie
21          {
22              Title = "Ghostbusters 2",
23              ReleaseDate = DateTime.Parse("1986-2-23"),
24              Genre = "Comedy",
25              Price = 9.99M
26          },
27 
28        new Movie
29        {
30            Title = "Rio Bravo",
31            ReleaseDate = DateTime.Parse("1959-4-15"),
32            Genre = "Western",
33            Price = 3.99M
34        }
35    );
36    
37 }

 

7.Code First Migrations calls the Seed method after every migration (that is, calling update-database in the Package Manager Console), and this method updates rows that have already been inserted, or inserts them if they don't exist yet.

這句話的意思是:在每一次數據庫遷移的時候,這個seed方法都會被調用,這個方法更新已經插入的行數據,或者插入行,如果這個行數據不存在。

8.下面的方法起到了一個更新插入的作用:

 

1 context.Movies.AddOrUpdate(i => i.Title,
2     new Movie
3     {
4         Title = "When Harry Met Sally",
5         ReleaseDate = DateTime.Parse("1989-1-11"),
6         Genre = "Romantic Comedy",
7         Rating = "PG",
8         Price = 7.99M
9     }

 

9.*因為Seed方法,在每次數據庫遷移的時候,都會執行。你不能僅僅是插入數據,因為你將要插入的數據,將在第一次數據庫遷移結束之后,已經存在數據庫中;

   *更新插入的操作可以預防錯誤,通過阻止你,插入已經存在的數據到數據庫中。但是它有個缺點:它重載了,所有你在測試項目時候改變的數據;

   因為有些測試數據,你不想改變:比如,你測試的時候,改變了數據,但是你不想這個數據在數據庫更新的時候,發生改變。這個時候你可以做一個新增的操作:新增一個數據庫中不存在的數據。

10.看一下這句代碼吧:context.Movies.AddOrUpdate(i => i.Title,這第一個傳到AddOrUpdate方法的參數,指定了一個屬性,用來檢查是否已經存在相同的行數據,對于我這個項目來說,我這個Title,可以做為這個屬性,因為它在List中每次都是唯一的;This code assumes that titiles are unique. If you manually add a duplicate title, you'll get the following exception the next time you perform a migration.

     Sequence contains more than one element 我們假想Title是唯一的,如果你手動添加了重復的Title,你將會在下次數據庫遷移的時候,報一個錯誤,了解更多,請參考鏈接的文章,哈哈,純人工翻譯的哦。因為博主喜歡英語,所以還是看外國人的資料學習編程了。MSDN很不錯的,
For more information about the AddOrUpdate method, see Take care with EF 4.3 AddOrUpdate Method..

11.現在我們來編譯一下整個項目吧,如果這這里不編譯的話,后面的步驟中將會出錯誤。

12.The next step is to create a DbMigration class for the initial migration. This migration creates a new database, that's why you deleted the movie.mdf file in a previous step.
這句話的意思是:我們接下來要為初始化數據庫遷移,創建一個DBMigration類,這個數據庫遷移創建一個新的數據庫,這也就是我們前面刪掉Movie.mdf文件的原因。


13.在程序包管理器控制臺中輸入:

add-migration Initial

我們看到:

 

14.Code First Migrations creates another class file in the Migrations folder (with the name {DateStamp}_Initial.cs ), and this class contains code that creates the database schema. The migration filename is pre-fixed with a timestamp to help with ordering. Examine the {DateStamp}_Initial.cs file, it contains the instructions to create the Movies table for the Movie DB. When you update the database in the instructions below, this {DateStamp}_Initial.cs file will run and create the the DB schema. Then the Seed method will run to populate the DB with test data.

這段話的意思是:Code First遷移,在Migration文件下,創建了另外一個類(類的文件名稱是:時間_Initiaal.cs),并且這個類包含了創建數據庫的代碼。這個文件以時間的命名方式便于排序管理。檢查這個文件,它包含了怎么為MovieDB創建Moviess數據庫表。當你按照下面的指令(等會我在控制器管理控制臺中輸入的指定),更新數據庫的時候,這個文件會執行,并且創建數據庫,然后這個Seed方法,也將會執行,為數據庫生成測試數據。


先看看看這個文件里面的代碼是啥樣的吧:

 

 1 namespace MvcMovie.Migrations
 2 {
 3     using System;
 4     using System.Data.Entity.Migrations;
 5     
 6     public partial class Initial : DbMigration
 7     {
 8         public override void Up()
 9         {
10             CreateTable(
11                 "dbo.Movies",
12                 c => new
13                     {
14                         ID = c.Int(nullable: false, identity: true),
15                         Title = c.String(),
16                         ReleaseDate = c.DateTime(nullable: false),
17                         Genre = c.String(),
18                         Price = c.Decimal(nullable: false, precision: 18, scale: 2),
19                     })
20                 .PrimaryKey(t => t.ID);
21             
22         }
23         
24         public override void Down()
25         {
26             DropTable("dbo.Movies");
27         }
28     }
29 }

 

同樣看看我們之前的Migration里面Configuration.cs代碼吧:

 

 1 namespace MvcMovie.Migrations
 2 {
 3     using MvcMovie.Models;
 4     using System;
 5     using System.Data.Entity;
 6     using System.Data.Entity.Migrations;
 7     using System.Linq;
 8 
 9     internal sealed class Configuration : DbMigrationsConfiguration<MvcMovie.Models.MovieDBContext>
10     {
11         public Configuration()
12         {
13             AutomaticMigrationsEnabled = false;
14         }
15 
16         protected override void Seed(MvcMovie.Models.MovieDBContext context)
17         {
18             context.Movies.AddOrUpdate(i => i.Title,
19         new Movie
20         {
21             Title = "When Harry Met Sally",
22             ReleaseDate = DateTime.Parse("1989-1-11"),
23             Genre = "Romantic Comedy",
24             Price = 7.99M
25         },
26 
27          new Movie
28          {
29              Title = "Ghostbusters ",
30              ReleaseDate = DateTime.Parse("1984-3-13"),
31              Genre = "Comedy",
32              Price = 8.99M
33          },
34 
35          new Movie
36          {
37              Title = "Ghostbusters 2",
38              ReleaseDate = DateTime.Parse("1986-2-23"),
39              Genre = "Comedy",
40              Price = 9.99M
41          },
42 
43        new Movie
44        {
45            Title = "Rio Bravo",
46            ReleaseDate = DateTime.Parse("1959-4-15"),
47            Genre = "Western",
48            Price = 3.99M
49        }
50    );
51         }
52     }
53 }

 

現在我們在,程序包管理器控制臺中輸入這個指令來創建數據庫,并運行seed方法:

update-database

我們可以看到:

If you get an error that indicates a table already exists and can't be created, it is probably because you ran the application after you deleted the database and before you executed update-database. In that case, delete theMovies.mdf file again and retry the update-database command. If you still get an error, delete the migrations folder and contents then start with the instructions at the top of this page (that is delete the Movies.mdf file then proceed to Enable-Migrations).

這句話的意思是:如果你運行上面的update-database指定,初始化數據表錯誤顯示:數據表已經存在不能被創建,很可能是因為你在刪除movie.mdf數據庫文件之后,運行了項目,沒有先執行updata-database指令。這種情況下,你可以再次刪除movie.mdf文件,然后重新執行update-database命令。如果仍然報錯,刪除這個Migration文件夾和里面的內容,重新按照我這篇文章剛開始的步驟,做一遍。。。


15.運行項目:在地址欄中輸入Movie。(我這里就不輸入Movie了,因為我改了路由配置,默認是Movie控制器下面的Index方法)可以看到seed方法里面的數據,都顯示出來了。

 

16.現在讓我們開始今天真正的任務:給Model添加一個新字段

打開Models文件夾下面的Movie.cs文件,在里面加入如圖所示的字段:

 

接著我們編譯一下項目吧。

 

17.Because you've added a new field to the Movie class, you also need to update the the binding white list so this new property will be included. Update the bind attribute for Create and Edit action methods to include the Ratingproperty:

這句話的意思是:因為你新增了一個字段到Movie類中,你同樣需要去為Create方法和Edit方法更新綁定Bind:

[Bind(Include = "ID,Title,ReleaseDate,Genre,Price,Rating")]

18.You also need to update the view templates in order to display, create and edit the new Rating property in the browser view.

Open the \Views\Movies\Index.cshtml file and add a <th>Rating</th> column heading just after the Price column. Then add a <td> column near the end of the template to render the @item.Rating value. Below is what the updated Index.cshtml view template looks like:

你同樣需要去更新視圖模板為了在新增和編輯的時候,去顯示你剛才添加的字段。  打開\Views\Movies\Index.cshtml文件,在Price字段后面,去新增一個<th>Rating</th>列標題,然后在這個視圖模板的后面,寫上要顯示的數據 @item.Rating,具體看圖片所示;

 

 

19.Next, open the \Views\Movies\Create.cshtml file and add the Rating field with the following highlighed markup. This renders a text box so that you can specify a rating when a new movie is created.

這句話的意思是:打開\Views\Movies\Create.cshtml 新增頁面,添加Rating字段,使用下面的高亮顯示的代碼,這會生成一個文本框,所以在新增的時候,你可以指定一個Rating就可以添加到數據庫中了。

如圖:

 

現在已經完成了新增字段的功能任務了,我們來運行一下項目》》》

可以看到:

又報錯了,數據庫遷移方面的錯誤。。

 

20.You're seeing this error because the updated Movie model class in the application is now different than the schema of the Movie table of the existing database. (There's no Rating column in the database table.)

這句話的意思是:你看到這個錯誤,是因為你更新了模型中的Movie,它現在和已經存在的Movie表中的不一樣,已經存在的Movie表中,是沒有Rating字段的!!!

21.

There are a few approaches to resolving the error:

  1. Have the Entity Framework automatically drop and re-create the database based on the new model class schema. This approach is very convenient early in the development cycle when you are doing active development on a test database; it allows you to quickly evolve the model and database schema together. The downside, though, is that you lose existing data in the database — so you don't want to use this approach on a production database! Using an initializer to automatically seed a database with test data is often a productive way to develope an application. For more information on Entity Framework database initializers, see Tom Dykstra's fantastic ASP.NET MVC/Entity Framework tutorial.
  2. Explicitly modify the schema of the existing database so that it matches the model classes. The advantage of this approach is that you keep your data. You can make this change either manually or by creating a database change script.
  3. Use Code First Migrations to update the database schema.

這里有一些方法,來解決這個問題:

1.讓EF基于新的實體類,自動的刪除和再創建數據庫。這個方法在開發項目的早期,是很方便實用的。但是這會讓你丟失之前已經存在數據庫中的數據,所以使用一個初始化器,來存儲數據庫中的測試數據是很好的一個解決方法。要了解更多,請看鏈接文章。

2.根據你的Model結構,修改數據庫結構。這個方法的優點是你的數據不會丟失。你可以手動修改數據庫,或者寫數據庫腳本來修改。

3.使用Code First Migration技術,來升級數據庫。

 

這個教程,我們使用方法3,即Code First Migration技術來升級數據庫。

 

22.Update the Seed method so that it provides a value for the new column. Open Migrations\Configuration.cs file and add a Rating field to each Movie object.

打開Configuration文件,在里面添加我們剛才新增的Rating字段到每一個Movie對象中。

 1 namespace MvcMovie.Migrations
 2 {
 3     using MvcMovie.Models;
 4     using System;
 5     using System.Data.Entity;
 6     using System.Data.Entity.Migrations;
 7     using System.Linq;
 8 
 9     internal sealed class Configuration : DbMigrationsConfiguration<MvcMovie.Models.MovieDBContext>
10     {
11         public Configuration()
12         {
13             AutomaticMigrationsEnabled = false;
14         }
15 
16         protected override void Seed(MvcMovie.Models.MovieDBContext context)
17         {
18             context.Movies.AddOrUpdate(i => i.Title,
19         new Movie
20         {
21             Title = "When Harry Met Sally",
22             ReleaseDate = DateTime.Parse("1989-1-11"),
23             Genre = "Romantic Comedy",
24             Price = 7.99M,
25             Rating="PG"
26         },
27 
28          new Movie
29          {
30              Title = "Ghostbusters ",
31              ReleaseDate = DateTime.Parse("1984-3-13"),
32              Genre = "Comedy",
33              Price = 8.99M,
34              Rating = "PG"
35          },
36 
37          new Movie
38          {
39              Title = "Ghostbusters 2",
40              ReleaseDate = DateTime.Parse("1986-2-23"),
41              Genre = "Comedy",
42              Price = 9.99M,
43              Rating = "PG"
44          },
45 
46        new Movie
47        {
48            Title = "Rio Bravo",
49            ReleaseDate = DateTime.Parse("1959-4-15"),
50            Genre = "Western",
51            Price = 3.99M,
52            Rating = "PG"
53        }
54    );
55         }
56     }
57 }
Code First Migration

然后,我們編譯一下項目。接著打開“程序包控制器管理臺”,輸入下面的指令:

add-migration Rating

 

23.The add-migration command tells the migration framework to examine the current movie model with the current movie DB schema and create the necessary code to migrate the DB to the new model. The name Rating is arbitrary and is used to name the migration file. It's helpful to use a meaningful name for the migration step.

When this command finishes, Visual Studio opens the class file that defines the new DbMIgration derived class, and in the Up method you can see the code that creates the new column.

這個add-migration Rating指令,告訴migration框架,用當前的MovieDB數據結構,去檢查當前的movie model,為數據庫遷移創建必要的代碼。這個Rating字段用來寫這個添加指令。使用有意義的名字,來進行這個步驟,是很有必要的。當這個指令完成后,VS打開這個類文件,并定義一個部分類,來繼承DbMigration類。看代碼就知道了:

 

 

 

24.我們再次運行項目吧,激動人心的時刻來了。。。錯!!!我們應該先要執行這個:

Build the solution, and then enter the update-database command in the Package Manager Console window.(這一步坑死我了,我忘記執行了)。

新增字段運行新增的指令,之后,還得運行更新數據庫的指令。就和db.SaveChanges()方法類似。這不執行完之后,才能是大功告成!!!

25.喜憂參半,之后,我們來運行項目吧。

可以看到:

 

 

 

 

這樣就完成了數據庫遷移技術的學習。歡迎大家評論,轉載,我是@放飛夢想的翅膀,畢業于武漢軟件工程職業學院。


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()