Skip to content

迁移冲突解决 ​

概述 ​

在团队协作开发中,多个开发者同时创建数据库迁移时容易发生冲突。本文介绍如何预防和解决迁移冲突。


常见冲突场景 ​

场景 1: 重复的迁移名称 ​

Developer A creates: 20240101_AddProductTable.cs
Developer B creates: 20240101_AddProductTable.cs (冲突!)

解决方案: 使用有意义的唯一命名

bash
# ❌ 不好的命名
dotnet ef migrations add Update

# ✅ 好的命名
dotnet ef migrations add AddPriceColumnToProducts
dotnet ef migrations add CreateOrderItemsTable

场景 2: 迁移顺序冲突 ​

主分支: Migration_001 → Migration_002
开发者A: Migration_001 → Migration_002 → Migration_A
开发者B: Migration_001 → Migration_002 → Migration_B

合并后冲突!

解决方案: 重新基于最新主分支生成迁移

bash
# 1. 拉取最新主分支
git pull origin main

# 2. 删除本地冲突的迁移
dotnet ef migrations remove

# 3. 重新生成迁移(会自动追加到末尾)
dotnet ef migrations add MergeWithLatestChanges

# 4. 验证迁移
dotnet ef database update

预防策略 ​

1. 团队规范 ​

markdown
## 迁移命名规范
- 格式: `{YYYYMMDD}_{Description}`
- 示例: `20240115_AddUserPreferencesTable`

## 提交流程
1. 拉取最新代码
2. 检查是否有未应用的迁移
3. 创建自己的迁移
4. 测试迁移成功
5. 提交代码前再次拉取并更新

2. CI/CD 检查 ​

yaml
# .github/workflows/migration-check.yml
name: Migration Check

on: [pull_request]

jobs:
  check-migrations:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Apply migrations
        run: dotnet ef database update
        env:
          ConnectionStrings__Default: ${{ secrets.TEST_DB }}
      
      - name: Check for pending changes
        run: |
          PENDING=$(dotnet ef migrations has-pending-model-changes)
          if [ "$PENDING" = "True" ]; then
            echo "Error: Model has pending changes. Please create a migration."
            exit 1
          fi

解决冲突 ​

方法 1: 手动合并迁移文件 ​

csharp
// 冲突的迁移 A
public partial class AddEmailToUsers : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.AddColumn<string>(
            name: "Email",
            table: "Users",
            type: "nvarchar(200)",
            nullable: true);
    }
}

// 冲突的迁移 B
public partial class AddPhoneToUsers : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.AddColumn<string>(
            name: "Phone",
            table: "Users",
            type: "nvarchar(20)",
            nullable: true);
    }
}

// ✅ 合并后的迁移
public partial class AddContactInfoToUsers : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        // 合并两个迁移的操作
        migrationBuilder.AddColumn<string>(
            name: "Email",
            table: "Users",
            type: "nvarchar(200)",
            nullable: true);
        
        migrationBuilder.AddColumn<string>(
            name: "Phone",
            table: "Users",
            type: "nvarchar(20)",
            nullable: true);
    }
}

方法 2: 重置迁移历史 ​

bash
# ⚠️ 仅在开发环境使用!

# 1. 删除所有迁移文件
rm Migrations/*.cs

# 2. 删除 __EFMigrationsHistory 表
dotnet ef database drop -f
dotnet ef database update

# 3. 重新创建初始迁移
dotnet ef migrations add InitialCreate

# 4. 应用到数据库
dotnet ef database update

最佳实践 ​

✅ 推荐做法 ​

  1. 频繁同步: 每天多次拉取主分支
  2. 小步迁移: 每次只做一个小的改动
  3. 及时沟通: 修改共享表前与团队沟通
  4. 自动化测试: CI/CD 自动应用迁移
  5. 文档化: 记录复杂迁移的目的

❌ 避免的陷阱 ​

  1. 不要修改已提交的迁移: 创建新迁移来修正
  2. 不要删除共享的迁移: 会影响其他人的数据库
  3. 不要忽略冲突: 立即解决,不要拖延
  4. 不要在迁移中写业务逻辑: 只做架构变更

总结 ​

策略效果难度
规范命名⭐⭐⭐ 中⭐ 低
频繁同步⭐⭐⭐⭐ 高⭐ 低
CI/CD 检查⭐⭐⭐⭐⭐ 高⭐⭐ 中
小步迁移⭐⭐⭐⭐ 高⭐⭐ 中

关键: 预防为主,及时沟通,自动化检测!

基于 MIT 许可发布