• 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 入门学习完毕,源码下载地址:

    源码下载

  • 相关阅读:
    用FOR XML PATH('') 实现一列多行拼接为一行
    RTC相关文章收集
    XML-RPC vs. RTC Format
    获取当前月份的第一天
    image读取流
    WAMP解决访问后显示"You don't have permission to access / on this server."
    cxGrid之checkbox小结
    CXGRID用法(取行、列值;定位选中某行等等)
    delphi显示Sqlite的Text字段
    使用TRoleAuth类对DataSnap服务端的接口授权
  • 原文地址:https://www.cnblogs.com/HelloZyjS/p/12730787.html
Copyright © 2020-2023  润新知