EF中 Code-First 方式的数据库迁移
Posted 山涧清泉
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EF中 Code-First 方式的数据库迁移相关的知识,希望对你有一定的参考价值。
原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/code-first-migrations-with-entity-framework/
系列目录:
- Relationship in Entity Framework Using Code First Approach With Fluent API【【使用EF Code-First方式和Fluent API来探讨EF中的关系】】
- Code First Migrations with Entity Framework【使用EF 做数据库迁移】
- CRUD Operations Using Entity Framework 5.0 Code First Approach in MVC【在MVC中使用EF 5.0做增删查改】
- CRUD Operations Using the Repository Pattern in MVC【在MVC中使用仓储模式,来做增删查改】
- CRUD Operations Using the Generic Repository Pattern and Unit of Work in MVC【在MVC中使用泛型仓储模式和工作单元来做增删查改】
- CRUD Operations Using the Generic Repository Pattern and Dependency Injection in MVC【在MVC中使用泛型仓储模式和依赖注入,来做增删查改】
前面的文章中,学习了EF 中的几种关系,一对一,一对多,多对多。但是相信大家肯定会有疑问:
1.我难道每次都要创建数据库么?
2.我怎么样从已经存在的表中,添加字段和移除字段呢?
3.当我向表中,添加字段或者移除字段,我怎么来避免丢失数据呢?
4.当数据库发生改变的时候,我怎么获取到创建数据库的脚本呢?
不用着急,这篇文章,我会向大家一一讲到:
首先,说说我们为什么要使用数据库迁移技术吧,因为我们的实体总是变动地很频繁,在上篇文章中,我们使用了数据库初始化策略来做,也就是每次当数据库不存在的时候,就创建数据库【类似还有几种初始化策略】,然而,当你的实体改变的时候,在使用这个策略,EF就会报错。而数据库迁移技术就可以帮到我们,我们不用每次都创建数据库。并且数据库迁移技术还可以为我们设置初始化的数据。
先看看项目结构吧:
我们需要建2个类库项目,还有一个控制台的程序:
Student类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EF.Core { public class Student { public int ID { get; set; } public string Name { get; set; } public int Age { get; set; } public string Sex { get; set; } } }
StudentMap类:
using EF.Core; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity.ModelConfiguration; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Ef.Data { public class StudentMap:EntityTypeConfiguration<Student> { public StudentMap() { this.HasKey(s => s.ID); this.Property(s => s.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); this.Property(s => s.Name).HasColumnType("nvarchar").HasMaxLength(50).IsRequired(); this.Property(s => s.Sex).HasColumnType("nvarchar").IsRequired(); this.Property(s => s.Age).IsRequired(); this.ToTable("Students"); } } }
EF上下文类:
using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Ef.Data { public class EFDbContext:DbContext { public EFDbContext() : base("name=DbConnectionString") { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new StudentMap()); //base.OnModelCreating(modelBuilder); } } }
数据库连接字符串:【在EF.Data的配置文件和控制台的项目的配置文件中都要写:】另外注意:这两个项目需要引入EF Server. 代表本机
<connectionStrings>
<add name="DbConnectionString" connectionString="Server=.;database=StudentEFDB;uid=sa;pwd=Password_1" providerName="System.Data.SqlClient" />
</connectionStrings>
connectionString=“Server=.;Database=AppsDB;Trusted_Connection=True” 也可以
控制台中:
using Ef.Data; using EF.Core; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EF.App { public class Program { static void Main(string[] args) { Console.WriteLine("你好,请输入姓名:"); string name = Console.ReadLine().Trim(); Console.WriteLine("请输入年龄:"); int result = 0; //转换成功,result是正确的结果 if (!int.TryParse(Console.ReadLine().Trim(), out result)) { Console.WriteLine("请输入正确格式的年龄"); return; } Console.WriteLine("请输入你的性别:"); string sex = Console.ReadLine(); using(var db=new EFDbContext()) { Student model = new Student() { Name = name, Sex = sex, Age = result }; //db.Set<Student>().Add(model);或者下面的 db.Entry(model).State = System.Data.Entity.EntityState.Added; db.SaveChanges(); } Console.Write("Success!"); Console.ReadKey(); } } }
运行之后,写入数据。
看下数据库中的数据:
好了,这就完成了第一阶段的准备工作:现在我们需要在Student实体中加一个字段Email,项目做一下变动:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EF.Core { public class Student { public int ID { get; set; } public string Name { get; set; } public int Age { get; set; } public string Sex { get; set; } public string Email { get; set; } } }
using EF.Core; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity.ModelConfiguration; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Ef.Data { public class StudentMap:EntityTypeConfiguration<Student> { public StudentMap() { this.HasKey(s => s.ID); this.Property(s => s.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); this.Property(s => s.Name).HasColumnType("nvarchar").HasMaxLength(50).IsRequired(); this.Property(s => s.Sex).HasColumnType("nvarchar").IsRequired(); this.Property(s => s.Age).IsRequired(); this.Property(s => s.Email).IsRequired(); this.ToTable("Students"); } } }
using Ef.Data; using EF.Core; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EF.App { public class Program { static void Main(string[] args) { Console.WriteLine("你好,请输入姓名:"); string name = Console.ReadLine().Trim(); Console.WriteLine("请输入年龄:"); int result = 0; //转换成功,result是正确的结果 if (!int.TryParse(Console.ReadLine().Trim(), out result)) { Console.WriteLine("请输入正确格式的年龄"); return; } Console.WriteLine("请输入你的性别:"); string sex = Console.ReadLine(); Console.WriteLine("请输入你的Email:"); string email = Console.ReadLine(); using(var db=new EFDbContext()) { Student model = new Student() { Name = name, Sex = sex, Age = result, Email=email }; //db.Set<Student>().Add(model);或者下面的 db.Entry(model).State = System.Data.Entity.EntityState.Added; db.SaveChanges(); } Console.Write("Success!"); Console.ReadKey(); } } }
运行之后:报错,很正常嘛,这肯定报错,因为我们的实体改了。。
怎么办呢??别着急,我们来启用数据库迁移技术:
在程序包控制台中输入:
Enable-Migrations
接着按回车键,在项目中就会生成Migration文件夹,自己去看看里面有啥东东吧。
然后打开Configuration类:修改一下代码:(必须把DbMigrationsConfiguration的参数改成自己程序里的DbContext的namespace+实际类名)
接着在程序包管理器控制台中输入:
Update-Database -Verbose
好了,现在运行一下项目吧:
看到了么,到这里就没报错了。运行完之后,我们看下数据库中的数据:
可以看到之前的数据也在,也就是数据没有丢失。是不是很神奇呢???
总结:这两篇文章总结了EF的一些使用,希望你喜欢。
题外篇:这里是使用EF中的数据库迁移技术。我们就可以随时随地的添加删除字段。而不用手动去删除数据库,那样会丢失数据。
现在,我就想不用数据库迁移呢?
我删掉之前生成的Migration文件夹【包括里面的类】,然后修改代码【删除刚才添加的Email字段】:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EF.Core { public class Student { public int ID { get; set; } public string Name { get; set; } public int Age { get; set; } public string Sex { get; set; } // public string Email { get; set; } } }
using EF.Core; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity.ModelConfiguration; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Ef.Data { public class StudentMap:EntityTypeConfiguration<Student> { public StudentMap() { this.HasKey(s => s.ID); this.Property(s => s.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); this.Property(s => s.Name).HasColumnType("nvarchar").HasMaxLength(50).IsRequired(); this.Property(s => s.Sex).HasColumnType("nvarchar").IsRequired(); this.Property(s => s.Age).IsRequired(); // this.Property(s => s.Email).IsRequired(); this.ToTable("Students"); } } }
using Ef.Data; using EF.Core; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EF.App { public class Program { static void Main(string[] args) { Console.WriteLine("你好,请输入姓名:"); string name = Console.ReadLine().Trim(); Console.WriteLine("请输入年龄:"); int result = 0; //转换成功,result是正确的结果 if (!int.TryParse(Console.ReadLine().Trim(), out result)) { Console.WriteLine("请输入正确格式的年龄"); return; } Console.WriteLine("请输入你的性别:"); string sex = Console.ReadLine(); //Console.WriteLine("请输入你的Email:"); //string email = Console.ReadLine(); using(var db=new EFDbContext()) { Student model = new Student() { Name = name, Sex = sex, Age = result, // Email=email }; //db.Set<Student>().Add(model);或者下面的 db.Entry(model).State = System.Data.Entity.EntityState.Added; db.SaveChanges(); } Console.Write("Success!"); Console.ReadKey(); } } }
运行之后,还肯定会报错的,因为已经没有数据库迁移了:
我们做如下修改:
using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Ef.Data { public class EFDbContext:DbContext { public EFDbContext() : base("name=DbConnectionString") { //把数据库初始化策略设置为null Database.SetInitializer<EFDbContext>(null); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new StudentMap()); //base.OnModelCreating(modelBuilder); } } }
然后运行项目,就不错报错了,这是不使用数据库迁移技术做到的。
看下数据库:
两种方式都可以,不过还是推荐官方的方式,数据库迁移技术。
以上是关于EF中 Code-First 方式的数据库迁移的主要内容,如果未能解决你的问题,请参考以下文章
20.1翻译系列:EF 6中自动数据迁移技术EF 6 Code-First系列
20.翻译系列:Code-First中的数据库迁移技术EF 6 Code-First系列