1. Core Data迁移的必要场景

手机应用就像在高速公路上行驶的汽车,数据库就是发动机。当我们给汽车升级涡轮增压器(修改数据模型)时,总要确保原来的传动系统(已有数据)还能正常运作。某购物APP从V1.0升级到V2.0时:

  • 新增「商品收藏夹」功能需添加新实体
  • 用户手机号字段需要拆分为国家区号+号码
  • 订单状态需要从字符串枚举改为数值类型

这些场景都需要核心数据模型的调整而不丢失已有数据。上周团队就因为直接在测试环境修改模型导致10万条测试数据丢失,最后用了半天时间恢复——这警示我们必须掌握正确的迁移方法。

2. 轻量级迁移原理解析

就像给汽车换轮胎不需要大修发动机,轻量级迁移能自动处理简单模型变更。当修改满足以下条件时:

// 原始模型(V1.0):
class User: NSManagedObject {
    @NSManaged var phone: String
}

// 新模型(V2.0):
class User: NSManagedObject {
    @NSManaged var countryCode: String  // 新增字段
    @NSManaged var phoneNumber: String  // 修改后的字段
}

// 初始化Core Data栈时自动处理
let container = NSPersistentContainer(name: "Model")
container.loadPersistentStores { description, error in
    // 设置自动迁移选项
    let options = [NSMigratePersistentStoresAutomaticallyOption: true,
                  NSInferMappingModelAutomaticallyOption: true]
    container.persistentStoreCoordinator.addPersistentStore(
        ofType: NSSQLiteStoreType,
        configurationName: nil,
        at: storeURL,
        options: options)
}

自动迁移的魔法在于系统自动生成映射模型(Mapping Model),就像数学中的导函数,能把旧数据转化为新结构。但这种魔法对以下变更就失效:

  1. 实体删除或重命名
  2. 字段数据类型变更(String→Int)
  3. 实体继承结构调整

3. 自定义迁移策略进阶

当需要在数据迁移时执行特定业务逻辑时,自定义迁移就是您的手术刀。某金融APP的安全升级案例:

// 原始模型:用户密码使用MD5存储
@NSManaged var password: String

// 新模型:改用PBKDF2加密
@NSManaged var salt: Data
@NSManaged var iterations: Int32
@NSManaged var encryptedPassword: String

// 自定义迁移策略类
class SecurityMigrationPolicy: NSEntityMigrationPolicy {
    @objc func transformPassword(oldValue: String) -> [String: Any] {
        // 生成随机盐值
        let salt = generateRandomSalt()
        let iterations = 10000
        
        // PBKDF2加密计算
        let encrypted = PBKDF2.deriveKey(password: oldValue, 
                                      salt: salt,
                                      iterations: iterations)
        
        // 返回加密结果字典
        return ["encryptedPassword": encrypted,
               "salt": salt,
               "iterations": iterations]
    }
}

// 在.xcmappingmodel文件中指定该策略类
// 映射关系配置为:password字段映射到自定义方法

此时系统会将旧密码逐一通过transformPassword方法转换。迁移策略的生命周期分为三个阶段:

  1. 准备阶段:验证新旧模型是否可映射
  2. 执行阶段:逐条处理每条记录
  3. 校验阶段:验证迁移后数据完整性

4. 数据一致性保障措施

数据库迁移就像器官移植手术,需要严密的防感染措施。某社交APP的迁移保障方案:

// 迁移前完整性检查
func preMigrationCheck() throws {
    let legacyModel = NSManagedObjectModel.mergedModel(from: [Bundle.main], 
                                                     forStoreMetadata: metadata)!
    let coordinator = NSPersistentStoreCoordinator(managedObjectModel: legacyModel)
    
    // 使用旧模型检查现有数据
    let store = try coordinator.addPersistentStore(
        ofType: NSSQLiteStoreType,
        configurationName: nil,
        at: oldStoreURL,
        options: nil)
    
    // 执行验证查询
    let context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    context.persistentStoreCoordinator = coordinator
    
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "User")
    request.predicate = NSPredicate(format: "age < 0") // 验证非法年龄值
    if let results = try? context.fetch(request), !results.isEmpty {
        throw MigrationError.dataCorruption
    }
}

// 迁移后验证
func validateAfterMigration(newContext: NSManagedObjectContext) {
    let request = NSFetchRequest<User>(entityName: "User")
    request.predicate = NSPredicate(format: "countryCode == nil OR phoneNumber == nil")
    
    guard let count = try? newContext.count(for: request), count == 0 else {
        rollbackToPreviousVersion()
        return
    }
    
    // 哈希校验
    let allUsers = try! newContext.fetch(NSFetchRequest<User>(entityName: "User"))
    let hashBefore = computeHash(for: allUsers)
    backupDatabase()
    let hashAfter = computeHash(for: allUsers)
    assert(hashBefore == hashAfter, "数据校验失败")
}

5. 技术实践关键点

5.1 应用场景对照表

场景类型 适用方案 示例
新增属性/实体 轻量级迁移 添加用户头像字段
删除实体 自定义迁移 移除过时的积分系统
数据类型转换 自定义映射 String日期转Date类型
字段拆分 组合策略 手机号拆分国家码和号码

5.2 优劣对比

轻量级迁移优势

  • 零代码实现
  • 系统自动生成映射
  • 执行速度快

自定义迁移优势

  • 处理复杂关系(1对多→多对多)
  • 数据清洗能力
  • 支持业务逻辑集成

5.3 避坑指南

  1. 模型版本快照:每次修改前都创建新版本,就像游戏的存档点
  2. 逐步迁移原则:不要跨多版本迁移,类似系统升级需要逐个版本升级
  3. 内存管理:批量处理大量数据时要分页处理,避免内存暴涨
  4. 模拟测试:使用内存存储进行迁移预演

6. 实战经验总结

某电商APP采用的分阶段迁移方案值得借鉴:

  1. 开发阶段使用轻量级迁移快速迭代模型
  2. 测试阶段发现字段类型变更需求后建立映射模型
  3. 预发布阶段编写自定义迁移策略处理加密升级
  4. 正式上线时采用分批次灰度迁移策略

数据迁移本质上是在时间维度维护数据结构的连续性。就像考古学家修复文物时,既要保持原有特征,又要适应现代保存需求。