標籤:
在Asp.net Mvc 和Entity FrameWork程式中,如果資料庫不存在,EF預設的行為是建立一個資料庫。如果模型類與已有的資料庫不匹配的時候,會拋出一個異常。
通過指定資料庫內容物件初始化器,可以執行刪除和重新建立資料庫,並用種子方法填充資料庫。
當Asp.net Mvc 應用程式每一次啟動並執行時候,Entity Framework 能夠自動建立(或者刪除重新建立)資料庫。你能夠指定每一次程式啟動並執行時候,或者模型與已有資料庫不匹配的時候執行 刪除重新建立操作,通過指定Seed 方法,EF能自動的調用Seed方法在你重新建立資料庫後自動的填充資料。
注意:在資料移轉中執行種子方法後,會將種子方法中的資料記錄還原成種子方法中的記錄值,也就是說不能儲存在U中I做的的更改。因為每次遷移後執行Update-Database命令更新資料後都要調用種子方法。
而採用初始化器的方式如果模型類沒有變化,就不會執行初始化器中的種子方法,所以在UI中更改或刪除記錄的變化 是儲存的。
第一種情境:在開發階段,模型類需要快速迭代,為了保持產生的資料庫與模型類一致,需要刪除重新建立資料庫,但會導致丟失測試的資料,所以使用EF資料庫初始化器並用種子方法自動填滿測試資料,以方便測試。
第一步:建立資料庫初始化器。
1、建立DropCreateDatabaseAlways<DbContext>資料庫初始化器。在 程式每次啟動並執行時候都執行刪除、重新建立資料庫操作
public class SchoolInitializer:DropCreateDatabaseAlways<SchoolContext>
{
protected override void Seed(SchoolContext context) { var students = new List<Student> { new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")}, new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")}, new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")}, new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")}, new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")}, new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")}, new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")}, new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")} }; students.ForEach(s => context.Students.Add(s)); context.SaveChanges();
2、建立DropCreateDatabaseIfModelChanges<DbContext>資料庫初始化器。當模型發生更改的時候,執行刪除、重新建立資料庫操作
public class SchoolInitializer:DropCreateDatabaseIfModelChanges<SchoolContext>
{
protected override void Seed(SchoolContext context)
{
var students = new List<Student>
{
new Student {FirstMidName ="張",LastName="三",EnrollmentDate=DateTime.Parse("1979-9-1")}
new Student {FirstMidName ="李",LastName="四",EnrollmentDate=DateTime.Parse("2000-9-1")},
new Student {FirstMidName ="王",LastName="二",EnrollmentDate=DateTime.Parse("1979-9-1")}
new Student {FirstMidName ="陳",LastName="五",EnrollmentDate=DateTime.Parse("2000-9-1")},
};
students.ForEach(s => context.Students.Add(s));
context.SaveChanges();
第2步:在應用程式中指定資料庫初始化器。有兩種方法
1、在Asp.Net Mvc 應用程式 根目錄的 Web.Config 的XML檔案中的<EntityFramework>節點中配置
<entityFramework> <contexts> <context type="ContosoUniversity.DAL.SchoolContext, ContosoUniversity"> <databaseInitializer type="ContosoUniversity.DAL.SchoolInitializer, ContosoUniversity" /> //disableDatabaseInitialization="true"
.可以關閉初始化器 </context> </contexts>
2、在全域應用程式設定檔Global.asax 中的 Application_Start 方法中通過代碼的方式指定。
Database.SetInitializer<SchoolContext>(new SchoolInitializer());
第二種情境:部署階段 如果需要在部署的產品中儲存初始化資料,比如在角色許可權系統中的超級管理使用者名、密碼資訊,以便能夠登入,或執行其他一些初始化操作,也需要定義和使用一個 資料庫上下文初始化器,只能使用 DropCreateDatabaseIfModelChanges<SchoolContext>
第一步:定義一個資料庫初始化器
public class MajorContextInitializer:DropCreateDatabaseIfModelChanges<MajorContext>
{
protected override void Seed(MajorContext context)
{
var themeList = new List<BootstrapTheme>()
{
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Stock" ,ThemeDescription="預設主題。黑色背景導航條,藍色背景標題", IsActived=true},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Cerulean" ,ThemeDescription="深藍色背景導航條,淺藍色背景標題", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Cosmo" ,ThemeDescription="天藍色背景導航條,天藍色背景標題", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Darkly" ,ThemeDescription="翠綠色背景導航條,藍黑色背景標題,黑色背景", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Flatly" ,ThemeDescription="翠綠色背景導航條,藍黑色背景標題", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Sandstone" ,ThemeDescription="綠色背景導航條,藍黑色背景標題", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Spacelab" ,ThemeDescription="深藍色背景導航條,深藍色背景標題", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Superhero" ,ThemeDescription="橘黃色背景導航條,橘黃色背景標題,小號字", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="United" ,ThemeDescription="硃紅色背景導航條,橘黃色背景標題", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Yeti" ,ThemeDescription="藍色背景導航條,藍色背景標題,小號字", IsActived=false}
};
//這裡如果不使用Foreach 語句遍曆,也可以使用 themeList.Foreach(s =>context.BootstrapThemes.AddOrUpdate(p =>p.ThemeName,s)) 執行upsert操作,以themeName 主題名稱作為區分不同的主題。
foreach (var theme in themeList)
{
var _theme = context.BootstrapThemes.Where(x => x.ThemeName == theme.ThemeName).FirstOrDefault();
if (_theme == null)
{
context.BootstrapThemes.Add(theme);
}
}
context.SaveChanges(); //這裡實際上並需要使用context.SaveChages().主要是方便調試,定位錯誤出在哪裡。
//既然使用靜態建構函式可以初始化主題,那麼也應該可以初始化其它DbSet 實體集成員。
var categoryList = new List<Category>()
{
new Category{ CategoryID=Guid.NewGuid().ToString(), CategoryName="專業動態",CategoryDescription="專業建設進展情況",NavbarIsShow=true,IndexPageIsShow=true, PriorOrder=1},
new Category{ CategoryID=Guid.NewGuid().ToString(), CategoryName="運行機制",CategoryDescription="制度建設情況",NavbarIsShow=true,IndexPageIsShow=true, PriorOrder=2},
new Category{ CategoryID=Guid.NewGuid().ToString(), CategoryName="教學隊伍",CategoryDescription="專業帶頭人、師資隊伍、團隊建設情況",NavbarIsShow=true,IndexPageIsShow=true, PriorOrder=3},
new Category{ CategoryID=Guid.NewGuid().ToString(), CategoryName="實踐條件",CategoryDescription="校內、校外實訓基地建設",NavbarIsShow=true,IndexPageIsShow=true, PriorOrder=4},
new Category{ CategoryID=Guid.NewGuid().ToString(), CategoryName="培養方案",CategoryDescription="人才培養方案",NavbarIsShow=true,IndexPageIsShow=true, PriorOrder=5},
new Category{ CategoryID=Guid.NewGuid().ToString(), CategoryName="校企合作",CategoryDescription="校企合作情況",NavbarIsShow=true,IndexPageIsShow=true, PriorOrder=6},
new Category{ CategoryID=Guid.NewGuid().ToString(), CategoryName="社會服務",CategoryDescription="社會服務情況",NavbarIsShow=true,IndexPageIsShow=true, PriorOrder=7},
new Category{ CategoryID=Guid.NewGuid().ToString(), CategoryName="政策法規",CategoryDescription="高等職業教育制度",NavbarIsShow=true,IndexPageIsShow=true, PriorOrder=8},
new Category{ CategoryID=Guid.NewGuid().ToString(), CategoryName="課程體系",CategoryDescription="課程體系構成",NavbarIsShow=true,IndexPageIsShow=true, PriorOrder=9}
};
foreach(var category in categoryList)
{
var _category = context.Categories.Where(x => x.CategoryName == category.CategoryName).FirstOrDefault();
if (_category == null)
{
context.Categories.Add(category);
}
}
context.SaveChanges(); //這裡實際上並需要使用context.SaveChages().主要是方便調試,定位錯誤出在哪裡。
//添加一條預設的專業名稱記錄;
var majorName = new MajorName { MajorNameID = Guid.NewGuid().ToString(), MajorNameText = "數控技術" };
if(context.MajorNames.Count() ==0)
{
context.MajorNames.Add(majorName);
}
context.SaveChanges(); //這裡實際上並需要使用context.SaveChages().主要是方便調試,定位錯誤出在哪裡。
base.Seed(context);
}
}
第二步:在資料庫內容物件中中定義一個資料庫靜態建構函式,在靜態建構函式中設定初始化器。則每一次調用資料庫內容物件的時候都要檢查資料庫中是否存在這些初始值,會降低程式的響應速度。 這種方法不是最佳實務。
public class MajorContext:DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Article> Articles { get; set; }
public DbSet<Course> Courses { get; set; }
public DbSet<Resource> Resources { get; set; }
public DbSet<BootstrapTheme> BootstrapThemes { get; set; }
public DbSet<MajorName> MajorNames { get; set; }
public MajorContext()
: base("MajorContext")
{ }
//靜態建構函式。MSDN:靜態建構函式用於初始化任何待用資料,或用於執行僅需執行一次的特定操作。在建立第一個執行個體或引用任何靜態成員之前,將自動調用靜態建構函式
static MajorContext()
{
//設定資料庫初始化器,它就在應用程式啟動並執行時候載入。
Database.SetInitializer<MajorContext>(new MajorContextInitializer());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) // OnModelCreating 方法重寫的目的是指定對應Dbse實體集的表格的名稱應該是單數,如果沒有此方法,資料庫中的表格名稱會按慣例為複數的名稱,如 Studnets、Courses
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Asp.net Mvc 資料庫上下文初始化器