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脚本中,先临时打开了允许插入主键的功能,用来插入自定义的主键值,然后又关闭了允许插入主键的功能.
为什么要在种子数据中,必须要指定主键的值呢?
因为可以确保,开发团队中的成员,在同一个迁移版本的情况下,他们拥有相同的主键数据.
将种子数据保存到数据库中,执行下列命令
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 入门学习完毕,源码下载地址:
- 上述文档参考自
种子数据