005 Entity Framework Core 2.x 种子数据

005 Entity Framework Core 2.x 种子数据


博客园文章Id:


   modelBuilder.Entity<Province>().HasData(new Province
            {
                ProvinceId = 1,  //此处一定要记得编写主键
                Name = "广东",
                Population = 90_000_000
            });

添加种子数据快照,执行下列命令

Add-Migration AddProvinceData

我们可以观察一下生成的迁移类

using Microsoft.EntityFrameworkCore.Migrations;

namespace AspEFCore.Data.Migrations
{
    public partial class AddProvinceData : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.InsertData(
                table: "Province",
                columns: new[] { "ProvinceId", "Name", "Population" },
                values: new object[] { 1, "广东", 90000000 });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DeleteData(
                table: "Province",
                keyColumn: "ProvinceId",
                keyValue: 1);
        }
    }
}

通过观察,我们了解到,这个类的大致意思是需要向Province表写入一条数据.

我们也可以生成sql,生成sql需要执行下列命令

script-Migration

生成的sql截图如下(生成的是所有迁移类要执行的sql脚本):

生成的sql
生成的sql

此处有问题需要注意一下,因为数据库中的表主键是自增的,但是我们在写种子数据的时候指定了主键的值,所以我们可以观察到,生成的sql脚本中,先临时打开了允许插入主键的功能,用来插入自定义的主键值,然后又关闭了允许插入主键的功能.

为什么要在种子数据中,必须要指定主键的值呢?

因为可以确保,开发团队中的成员,在同一个迁移版本的情况下,他们拥有相同的主键数据.

将种子数据保存到数据库中,执行下列命令

update-database

此时如果我们发现种子数据写错了,我们需要修改种子数据,那么会怎么样呢?

修改的种子数据:

modelBuilder.Entity<Province>().HasData(new Province
{
    ProvinceId = 2,
    Name = "广东省",
    Population = 90_011_002
});

执行 add-Migration Edit2

生成了新的种子数据迁移类
生成了新的种子数据迁移类

我们发现EFCore会将原来的数据先进行删除,然后再进行重新写入.

那么如果我们只修改内容,而不是修改主键Id,那么EFCore,就只会生成对这条数据进行Update的迁移类的描述了.

new Province()
{
    ProvinceId = 3,
    Name = "江苏省",
    Population = 100_000_001,
    Cities = new List<City>()
    {
        new City(){CityId = 31,Name = "南京"},
        new City(){CityId = 32,Name = "苏州"},
        new City(){CityId = 33,Name = "无锡"}
    }
}

那么我们在添加种子数据的时候,将他们的关联数据也一起添加是否可以呢?
答案是不可以的,会报以下错误.

The seed entity for entity type 'Province' with the key value 'ProvinceId:3' cannot be added because it has the navigation 'Cities' set. To seed relationships you need to add the related entity seed to 'City' and specify the foreign key values {'ProvinceId'}.

上面的意思是,因为存在Citits外键,所以我们必须单独编写City的种子数据,并且要为这些数据添加ProvinceId外键.

所以我们必须要在子表数据中指明父表主键Id

modelBuilder.Entity<Province>().HasData(
    new Province
    {
        ProvinceId = 2,
        Name = "广东省",
        Population = 90_011_002
    },
    new Province()
    {
        ProvinceId = 3,
        Name = "江苏省",
        Population = 100_000_001,
    }

    );

modelBuilder.Entity<City>().HasData(
    new List<City>
    {
        new City(){ProvinceId =3, CityId = 31,Name = "南京"}
        new City(){ProvinceId =3, CityId = 32,Name = "苏州"},
        new City(){ProvinceId =3, CityId = 33,Name = "无锡"}
    }
    );

如上述写法就可以了.

还有一种应用场景,City模型中,没有表述外键表关系的字段例如没有ProvinceId,那么我们应该怎么,写入种子数据到数据库中呢?我们可以使用匿名类的方式

modelBuilder.Entity<City>().HasData(
new { ProvinceId = 3, CityId = 31, Name = "南京" },
new { ProvinceId = 3, CityId = 32, Name = "苏州" },
new { ProvinceId = 3, CityId = 33, Name = "无锡" },
new { ProvinceId = 3, CityId = 34, Name = "溧阳" });

执行 add-migration edit3 命令,观察生成的迁移类.

迁移类
迁移类

我们可以发现EFCore 会先移除原本的外键,然后自己创建了主键.

在使用Guid作为主键时,我们一定要使用固定的Guid值,否则每一次迁移生成的Guid都是不一样的.所以我们应该这么做.

 var studentId = new Guid("6F9619FF-8B86-D011-B42D-00C04FC964FF");   //明确一个固定的Id,否则每次迁移的Guid值都是不一样的,不利于团队开发.
            modelBuilder.Entity<Student>().HasData(
                new Student { StudentId = studentId,Name = "张三"}
                );

到此EntityFrameworkCore 入门学习完毕,源码下载地址:

源码下载

posted @ 2020-04-19 11:36  HelloZyjS  阅读(321)  评论(0编辑  收藏  举报