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

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

    或者:http://www.codeproject.com/Articles/801545/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

    <connectionStrings>
        <add name="DbConnectionString" connectionString="Server=.;database=StudentEFDB;uid=sa;pwd=Password_1" providerName="System.Data.SqlClient" />
      </connectionStrings>

    控制台中:

    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类:修改一下代码:

    接着在程序包管理器控制台中输入:

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

     

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

     

     看下数据库:

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

     

     

     

  • 相关阅读:
    21.Merge Two Sorted Lists 、23. Merge k Sorted Lists
    34. Find First and Last Position of Element in Sorted Array
    leetcode 20. Valid Parentheses 、32. Longest Valid Parentheses 、301. Remove Invalid Parentheses
    31. Next Permutation
    17. Letter Combinations of a Phone Number
    android 常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )及屏幕适配注意事项
    oc 异常处理
    oc 类型判断
    oc Delegate
    oc 协议
  • 原文地址:https://www.cnblogs.com/caofangsheng/p/5798324.html
Copyright © 2011-2022 走看看