zoukankan      html  css  js  c++  java
  • EF中 Code-First 方式的数据库迁移

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/code-first-migrations-with-entity-framework/

    系列目录:

    前面的文章中,学习了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);
           }
        }
    }
    复制代码

     然后运行项目,就不错报错了,这是不使用数据库迁移技术做到的。

     看下数据库:

    两种方式都可以,不过还是推荐官方的方式,数据库迁移技术。

  • 相关阅读:
    初学python遇到的第一个坑
    返回列表中最长的连续字符串
    输入一个数字,求每一位相加之和
    判断一个数是否为素数
    编写一个函数,它接受一个或多个单词的字符串,并返回相同的字符串,但所有五个或多个字母的单词都颠倒过来
    判断10步能不能回到原点
    完成方法/函数,以便将破折号/下划线分隔的单词转换为驼峰式大小写
    求公共汽车上的人数
    写一个函数,返回不同的计数
    对一个数的每一位数字求平方
  • 原文地址:https://www.cnblogs.com/sjqq/p/7684501.html
Copyright © 2011-2022 走看看