EFCore 2.1 出来有一段时间了, 里面的新功能还没怎么用, 今天研究下如何使用 EF Core 2.1 添加种子数据.
这部分的官方文档地址是:
我们在开发时总是需要添加一些种子数据的, 所以这个功能还是比较有用的.
准备工作
我建立了一个 ASP.NET Core 项目, 里面有几个 Model, 其中一个是省份 Province, 另一个是城市 City:
里面还涉及到其它的 Model, 不过本文用不到, 就不贴了.
该项目使用的数据库是 MSSQL LocalDB. 并已经做好了上述 Models 的迁移工作.
该数据库里面存在过一些数据, 但是现在都被我删除了.
添加第一个种子数据
直接在 DBContext 的 OnModelCreating 方法里使用 HasData() 方法:
这里我添加了一个省份的种子数据, 并写上了主键 Id 的值.
数据库该表的主键 Id 是 int 自增的. Id 为 1 的数据曾经存在过, 但是被我删除了.
然后看看会发生什么
生成的迁移类
命令: Add-Migration Xxx
看一下生成的迁移类的内容:
生成的 SQL 脚本
命令: Script-Migration
这是里面关于插入数据的部分:
迁移到数据库
命令: Update-Database -Verbose
结果是成功的.
看红线那两句话, EFCore 在执行的过程中临时更改了设置, 可以插入主键的值, 然后又禁用了插入主键.
数据库里面的数据
虽然曾经存在过 Id 为 1 的数据 (然后被删除了), 但是 Id 为 1 的种子数据仍然可以插入进去.
种子数据的主键必须有值
我再添加一个没有主键 Id 值的种子数据:
然后 Add-Migration, 看看会发生什么:
报错了, 所以主键值是必填的.
当我填写了主键值之后, 一切都是好用的了:
更改现有的种子数据
我在 HasData 方法里更改了现有的种子数据, 但是主键的值并没有改:
执行 Update-Database 时的 SQL 语句:
可以看到是根据主键对数据库里面的数据进行 Update 动作.
其结果也和我想的一样, 就是更新了现有的数据:
如果我把 HasData 里种子数据的主键值修改了
我把四川的主键从 2 改为 3.
看下生成的迁移文件:
先删除了之前添加的 Id 为 2 的种子数据, 然后把插入了一笔 Id 为 3 的数据.
看下 SQL:
也是先 Delete, 再 Insert.
数据库里:
种子数据为什么要指定主键的值?
因为在团队开发时, 这样可以确保不同的开发人员, 电脑, 服务器上, 在同一个迁移版本具有相同的种子数据.
添加关联种子数据
Province 和 City 是一对多的关系, 也就是说一个 Province 可以有多个 City, 而且它们之间有导航属性.
下面看看一次性添加 Province 和 City 是否可以行, 我直接在 HasData 方法里这样写:
然后 Add-Migration
这样做不行. 我必须单独添加 City 的种子数据, 并且设置好外键.
所以正确的做法是:
这次 Add-Migration 没有报错, 迁移也成功了, 看一下最后的数据:
OK
如果无法在 Model 里设置主键 / 外键
有时, 我们在主从关系的 Model 里不明确定义外键; 有时候我们 Model 的主键是 private set 的;
这时我们就无法在 HasData 里设置主键 / 外键的值了, 那么如何来添加种子数据呢?
答案就是使用匿名类.
我把 City Model 里的外键去掉 (导航属性仍然保留, 和 Province 的主从关系依然存在):
然后就可以这样添加种子数据:
迁移后的数据:
结果仍然如预期一样.
如果主键是 Guid 类型呢?
看下数据:
貌似没问题.
如果我不修改这个种子数据, 再执行一次迁移呢?
看一下这时的迁移文件:
删除原来的数据, 再插入一个新的数据..
数据库里也是这样的:
所以最好的办法是把 Guid 的值放在一个变量里:
然后再操作一遍:
这样就不会出现 "把原有数据删掉, 再重新插入" 这种操作了.
其它
使用 context.Database.EnsureCreated() 会创建一个新的数据库, 并包含有种子数据. 但是如果数据库已经存在了, 那么 EnsureCreated() 不会更新数据库, 也不会添加种子数据了.
来源: https://www.cnblogs.com/cgzl/p/9868501.html