EF Core Code First Migration如何为SQLite现有表新增非空唯一列并填充自定义唯一值
你之前的两个方案都会生成重复值,核心问题是你把唯一ID生成的逻辑放在了C#代码的静态参数/字符串插值里,这些逻辑只会在迁移执行前计算一次,最终落到数据库执行的都是固定值,自然所有行都会拿到同一个结果。
因为你需要使用C#侧的自定义函数生成唯一ID,无法依赖数据库内置函数,可按以下步骤实现需求:
实现逻辑
- 先新增可空的
PublicId字段,不设置默认值,暂时不添加唯一索引 - 读取
Customers表所有现有记录的主键ID列表 - 遍历每个主键ID,调用你的自定义函数生成唯一的
PublicId,逐行执行更新 - 所有行更新完成后,将
PublicId字段修改为非空约束 - 最后添加唯一索引
示例迁移代码
protected override void Up(MigrationBuilder migrationBuilder) { // 步骤1:新增可空的PublicId列,无默认值 migrationBuilder.AddColumn<string>( name: "PublicId", table: "Customers", nullable: true); // 步骤2:读取所有现有客户的主键ID List<int> customerIds = new List<int>(); // 这里用SQLite连接读取数据,连接字符串可从迁移上下文获取,也可直接传入 using var connection = new Microsoft.Data.Sqlite.SqliteConnection("你的SQLite数据库连接字符串"); connection.Open(); using (var command = connection.CreateCommand()) { command.CommandText = "SELECT Id FROM Customers"; using var reader = command.ExecuteReader(); while (reader.Read()) { customerIds.Add(reader.GetInt32(0)); } } // 步骤3:逐行生成唯一ID并更新 foreach (var id in customerIds) { // 替换为你自己的自定义唯一ID生成函数 string customUniqueId = YourCustomGenerateIdFunction(); migrationBuilder.Sql($"UPDATE Customers SET PublicId = '{customUniqueId}' WHERE Id = {id}"); // 生产环境建议使用参数化写法,避免SQL注入风险 } // 步骤4:将PublicId修改为非空约束 migrationBuilder.AlterColumn<string>( name: "PublicId", table: "Customers", nullable: false, oldClrType: typeof(string), oldNullable: true); // 步骤5:添加唯一索引 migrationBuilder.CreateIndex( name: "IX_Customers_PublicId", table: "Customers", column: "PublicId", unique: true); }
注意事项
- 若表数据量较大,建议分批执行更新操作,避免单次迁移执行时间过长
- 自定义ID生成函数需要确保输出全局唯一,避免出现重复值导致后续添加唯一索引失败
- 生产环境执行迁移前务必做好数据备份
内容的提问来源于stack exchange,提问作者Brad Collins
相关产品推荐
相关产品推荐

