Entity Framework Core种子数据Data-Seeding

目录
  • 一、什么是Data-Seeding
  • 二、初始化方法
    • 1、模型中配置
    • 2、手动迁移时添加
    • 3、自定义初始化逻辑
  • 三、Data-Seeding本质
    • 1、首次迁移
    • 2、修改不是主键的数据
    • 3、删除数据
    • 4、修改主键数据
  • 四、总结

一、什么是Data-Seeding

Data-Seeding是EntityFrameworkCore 2.1以上版本新增加的特性。在项目刚开始的时候,我们往往是需要初始化一些基础数据到数据库中,通过Data-Seeding特性就可以实现这一功能。本篇文章我们将讲解如何进行数据初始化。

二、初始化方法

具体的数据初始化方法分为如下三种:

  • 模型中配置。这种是通过调用HasData()方法。
  • 手动迁移时添加。
  • 自定义初始化逻辑。

下面我们分别来讲解如何使用这三种方式进行数据迁移。

1、模型中配置

这种方式是通过调用HasData()方法实现的。这种也是我在项目开发过程中,经常使用的。这种方式是在数据上下文类中重写OnModelCreating()方法,我们先看HasData()方法的定义:

可以看到,方法的参数可以是Blog类型的数组,具体代码如下:

using EFCore.Model;
using Microsoft.EntityFrameworkCore;

namespace EFCore.Data
{
    /// <summary>
    /// 数据上下文
    /// </summary>
    public class EFDbContext:DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=EFTest;User ID=sa;Password=123456;");
        }

        public DbSet<Blog> Blogs { get; set; }

        /// <summary>
        /// 重写OnModelCreating方法
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // 针对Blog实体添加种子数据
            modelBuilder.Entity<Blog>().HasData(
                new Blog()
                {
                    // Id字段要赋值,否则会报错
                    Id=1,
                    Name="ef core"
                },
                new Blog()
                {
                    Id=2,
                    Name="ASP.NET Core"
                },
                new Blog()
                {
                    Id=3,
                    Name="图解数据结构"
                }
                );
            base.OnModelCreating(modelBuilder);
        }
    }
}

我们注意到:默认情况下会自动设置Id列为主键,并且是自动增长的。但是这里要设置Id的值,即使Id是自动生成的主键,否则会报下图所示的错误:

添加完种子数据以后,我们运行程序,查看输出结果:

查看数据库:

这样就生成了数据库和表,而且表里面也有了初始化数据。

假如这时候我们想增加一条数据,代码如下:

using EFCore.Model;
using Microsoft.EntityFrameworkCore;

namespace EFCore.Data
{
    /// <summary>
    /// 数据上下文
    /// </summary>
    public class EFDbContext:DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=EFTest;User ID=sa;Password=123456;");
        }

        public DbSet<Blog> Blogs { get; set; }

        /// <summary>
        /// 重写OnModelCreating方法
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // 针对Blog实体添加种子数据
            modelBuilder.Entity<Blog>().HasData(
                new Blog()
                {
                    // Id字段要赋值,否则会报错
                    Id=1,
                    Name="ef core"
                },
                new Blog()
                {
                    Id=2,
                    Name="ASP.NET Core"
                },
                new Blog()
                {
                    Id=3,
                    Name="图解数据结构"
                },
                // 新增加一条数据
                new Blog()
                {
                    Id=4,
                    Name="C#高级编程"
                }

                );
            base.OnModelCreating(modelBuilder);
        }
    }
}

这时候还能不能用刚才的方法呢?我们这时在运行程序,查看结果:

这时候程序执行失败了,而且表里面的数据也没有增加。这说明context.Database.EnsureCreated()方法只有在第一次执行的时候才会有效,以后数据进行更改后就无效了。那么有什么方式可以实现呢?这时只有通过命令行进行迁移或者通过context.Database.Migrate方法调用生成的迁移类才能对数据的更改有效。

我们把刚才生成的数据库删掉,新增加的那条数据注释掉,然后使用命令行迁移的方式生成数据库表,首先添加迁移:

然后更新数据库:

更新完数据库以后,我们在HasData()方法里面添加一条数据,然后再次执行上面的添加迁移和更新数据库的命令,发现这时候数据库里面会添加新增加的数据。

在执行完第二次添加迁移命令后,如果不使用更新数据库命令,也可以通过代码的方式进行迁移,这就是调用context.Database.Migrate命令,代码如下:

using EFCore.Data;
using Microsoft.EntityFrameworkCore;
using System;

namespace EFCore.Con
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            EFDbContext dbContext = new EFDbContext();
            // 迁移
            dbContext.Database.Migrate();
            //bool tfTrue = dbContext.Database.EnsureCreated();
            //if(tfTrue)
            //{
            //    Console.WriteLine("数据库创建成功!");
            //}
            //else
            //{
            //    Console.WriteLine("数据库创建失败!");
            //}

            Console.ReadKey();
        }
    }
}

这时会自动调用最新的迁移文件去更新数据库。

注意:调用该方法对数据的更改只有在迁移时才能生效,也就是说只有通过命令进行迁移或者通过context.Database.Migrate方法调用生成的迁移类才能对数据更改有效。而调用context.Database.EnsureCreated()方法只有在第一次执行的时候才有效,但数据进行更改后将无效。

这种方式有两种限制:

  • 必须指定主键的值(即使主键由数据库自动生成也要指定值)。
  • 添加的必须是静态数据,没有任何的依赖。比如添加的Id主键的值在其它表里面有引用就不可以。

2、手动迁移时添加

这种方式在这里不进行讲解,有兴趣的可以参考微软的官方文档。

3、自定义初始化逻辑

执行数据种子设定的一种简单而有效的方法是在主应用程序逻辑开始执行之前使用使用DbContext.SaveChanges()。代码如下:

using EFCore.Data;
using EFCore.Model;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;

namespace EFCore.Con
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            //EFDbContext dbContext = new EFDbContext();
            //// 迁移
            //dbContext.Database.Migrate();
            ////bool tfTrue = dbContext.Database.EnsureCreated();
            ////if(tfTrue)
            ////{
            ////    Console.WriteLine("数据库创建成功!");
            ////}
            ////else
            ////{
            ////    Console.WriteLine("数据库创建失败!");
            ////}

            #region 使用自定义初始化逻辑
            using(EFDbContext context=new EFDbContext())
            {
                context.Database.EnsureCreated();

                var testBlog = context.Blogs.FirstOrDefault(p => p.Name == "C#");
                if(testBlog == null)
                {
                    // 添加数据
                    context.Blogs.Add(new Blog()
                    {
                        Name = "C#"
                    });
                }

                // 保存数据
                context.SaveChanges();
            }
            #endregion
            Console.ReadKey();
        }
    }
}

通过这种自定义逻辑的方式也可以添加种子数据。如果HasData()方法里面添加了种子数据,那么会先把HasData()方法里面的种子数据添加到数据库中。如果没有名称为C#的数据,则还会在添加一条数据。

如果有了该数据,就不会再添加了。

注意:这种方式新增数据的时候就不能再给主键Id赋值了,因为是先生成数据库,自动设置Id为主键,在添加数据的时候会自动赋值。

三、Data-Seeding本质

  • 当调用HasData()方法首次迁移时,实质上是调用MigrationBuilder类中InsertData方法进行插入。
  • 当调用HasData()方法更改数据(未更改主键)时,实质上是调用MigrationBuilder类中UpdateData方法进行更新操作。
  • 当调用HasData()方法移除数据或更改主键时,实质上是调用MigrationBuilder类中DeleteData方法进行删除操作或者删除和更新操作。

1、首次迁移

我们在第一次执行完添加迁移命令以后,会生成一个迁移文件,如下图所示:

可以看到这时就是调用的InsertData方法来新增数据。

2、修改不是主键的数据

我们修改数据,将ef core修改为ef core 3.1.1,如下图所示:

修改完以后我们在执行迁移命令,如图所示:

这时在去看生成的迁移文件:

这时执行的就是UpdateData方法。

3、删除数据

接着我们把Id为1的数据在代码里面注释掉模拟删除操作,在执行迁移命令:

在看生成的迁移文件:

可以看到这次就是执行的DeleteData方法。

4、修改主键数据

我们在把Id为2的数据修改为6:

在执行迁移:

查看生成的迁移文件:

这次就是先执行DeleteData方法,然后在执行InsertData方法。

四、总结

针对种子数据初始化,主要有上面的三种方式,比较推荐的是第一种和第三种,可以根据自己的使用情况来选择适合自己的。

到此这篇关于Entity Framework Core种子数据Data-Seeding的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Entity Framework Core批处理SQL语句

    在Entity Framework Core (EF Core)有许多新的功能,最令人期待的功能之一就是批处理语句.那么批处理语句是什么呢?批处理语句意味着它不会为每个插入/更新/删除语句发送单独的请求,它将在数据库的单次请求中批量执行多个语句.在这篇文章中,让我们看看它是如何工作的,并将结果与EF6进行比较. EF Core将一次准备多个语句,然后在单次请求中执行它们,所以能提供了更好的性能和速度.让我们看看它是如何工作的.我们将借助SQL Server Profiler来捕获实际生成和执行的

  • Entity Framework Core对Web项目生成数据库表

    一.引言 这篇文章中我们讲解如何在Web项目中使用EntityFrameworkCore,并生成数据库表,这里以ASP.NET Core WebApi为例讲解.还是采用分层的结构.创建后的项目整体结构如下图所示: 项目结构: EFCoreWeb.API:ASP.NET Core WebApi项目,用来提供Web功能,在项目中会引用EFCoreWeb.Data. EFCoreWeb.Data:类库项目,基于.NET Core的类库.存放的是与EFCore相关的操作. EFCoreWeb.Model

  • Entity Framework Core中执行SQL语句和存储过程的方法介绍

    无论ORM有多么强大,总会出现一些特殊的情况,它无法满足我们的要求.在这篇文章中,我们介绍几种执行SQL的方法. 表结构 在具体内容开始之前,我们先简单说明一下要使用的表结构. public class Category { public int CategoryID { get; set; } public string CategoryName { get; set; } } 在Category定义了两个字段:CategoryID.CategoryName. public class Sam

  • Entity Framework Core延迟加载(懒加载)用法

    众所周知在EF 6 及以前的版本中,是支持懒加载(Lazy Loading)的,可惜在EF Core 并不支持,必须使用Include方法来支持导航属性的数据加载.不过现在EF Core的开发团队打算恢复对这一功能的支持(目前还未发布,不过可以在Github上面下载进行测试). 懒加载 懒加载也可以叫做按需加载.延迟加载.可以分两方面来理解,一方面指暂时不需要该数据,不用在当前马上加载,而可以推迟到使用它时再加载:另一方面指不确定是否将会需要该数据,所以暂时请不要加载,待确定需要后再加载它.懒加

  • Entity Framework Core生成数据库表

    目录 一.引言 二.具体示例 1.代码生成 2.程序包管理器控制台迁移 1.安装Microsoft.EntityFrameworkCore.Tools包 2.添加迁移命令 3.更新数据库 3.命令行迁移 1.添加迁移 2.更新数据库 三.总结 一.引言 生成数据库表有下面的三种方式: 代码生成. 程序包管理器控制台迁移. 命令行迁移. 下面分别介绍上面的三种方法. 二.具体示例 1.代码生成 在程序里面执行下面的代码可以在运行时生成数据库: dbContext.Database.EnsureCr

  • Entity Framework Core使用控制台程序生成数据库表

    目录 一.引言 1.添加实体类 2.添加Mircosoft.EntityFrameworkCore 二.生成数据库表 1.代码生成 2.程序包管理器控制台迁移 1.安装Microsoft.EntityFrameworkCore.Tools包 2.添加迁移 3.更新数据库 3.命令行迁移 一.引言 我们使用Code First的方式来生成数据库表,我们先讲解如何在控制台项目中生成数据库表. 在前面的文章中,我们是直接在控制台项目中安装的Mircosoft.EntityFrameworkCore,在

  • Entity Framework Core相关包的概念介绍与安装

    一.引言 我们以Entity Framework Core 最新版本3.1.1进行讲解,在正式的学习之前,我们第一步是要使用EF Core中的安装包,这时候需要明确的知道到底需要安装哪些包,我们下面先来讲解EF Core中需要使用到的一些包. 二.相关包极其概念 1.Microsoft.EntityFrameworkCore Microsoft.EntityFrameworkCore:Entity Framework Core is a lightweight and extensible ve

  • 对Entity Framework Core进行单元测试

    一.引言 我们先来讲解如何对EntityFrameworkCore进行单元测试,这里我们使用内存数据库进行测试.使用内存数据库需要安装Microsoft.EntityFrameworkCore.InMemory这个包. 二.创建测试项目 我们还是以上面文章中创建的项目为例,在解决方案中添加一个测试项目,这里选择使用xUnit作为测试项目: 创建完成后的项目结构如下图所示: 我们首先在EFCoreTest项目中安装Microsoft.EntityFrameworkCore和Microsoft.En

  • Entity Framework Core实现Like查询详解

    在Entity Framework Core 2.0中增加一个很酷的功能:EF.Functions.Like(),最终解析为SQL中的Like语句,以便于在 LINQ 查询中直接调用. 不过Entity Framework 中默认提供了StartsWith.Contains和EndsWith方法用于解决模糊查询,那么为什么还要提供EF.Functions.Like,今天我们来重点说说它们之间的区别. 表结构定义 在具体内容开始之前,我们先简单说明一下要使用的表结构. public class C

  • Entity Framework Core种子数据Data-Seeding

    目录 一.什么是Data-Seeding 二.初始化方法 1.模型中配置 2.手动迁移时添加 3.自定义初始化逻辑 三.Data-Seeding本质 1.首次迁移 2.修改不是主键的数据 3.删除数据 4.修改主键数据 四.总结 一.什么是Data-Seeding Data-Seeding是EntityFrameworkCore 2.1以上版本新增加的特性.在项目刚开始的时候,我们往往是需要初始化一些基础数据到数据库中,通过Data-Seeding特性就可以实现这一功能.本篇文章我们将讲解如何进

  • Entity Framework Core更新时间映射

    时间字段 在真实的开发中,为了跟踪数据的变化,一般会在数据表里面有CreatedTime和UpdatedTime两列.CreatedTime表示创建时间,新增一条数据的时候,会更新CreatedTime列的值.UpdatedTime表示更新时间,更新数据的同时也会更新UpdatedTime列的值,这时候就需要对应的映射来配置.我们修改Blog类,增加这两个时间字段: using System; namespace EFCore.Model { public class Blog { public

  • Entity Framework Core表名映射

    表名映射 我们知道:如果是在默认情况下,使用EFCore Code First的方式生成的表名跟数据上下文类中定义的实体属性的名称是一致的,例如: public DbSet<Blog> Bloges123 { get; set; } 这里定义的属性名称是Bloges123,那么最后数据库中生成的表名也叫Bloges123.看下面的测试. 我们首先添加迁移,每次迁移都会生成一个对应的迁移记录类,代码如下图所示: 可以看到,这里显示创建表的名称就是Bloges123.最后更新数据库,更新完成以后查

  • Entity Framework Core关联删除

    目录 数据库关联删除行为 定义实体 Fluent API 配置关联实体 创建表结构 EF Core 关联实体删除行为 总结 DeleteBehavior.Cascade DeleteBehavior.SetNull DeleteBehavior.ClientSetNull DeleteBehavior.Restrict 关联删除通常是一个数据库术语,用于描述在删除行时允许自动触发删除关联行的特征:即当主表的数据行被删除时,自动将关联表中依赖的数据行进行删除,或者将外键更新为NULL或默认值. 数

随机推荐