iOS - objective-c中realm的迁移

上一章节中我们学习了objective-c中realm的对应关系,例子中我们涉及到两种模型关系的对应,但是很多实际项目开发中,我们还会涉及到数据库迁移的问题。我们一起来让我们来探索 Realm 中数据库迁移的方案。

数据库迁移大致分为以下几种情况:
1.数据结构迁移
2.数据迁移
3.属性重命名
4.多版本增量迁移

场景一:
  • 一 . 数据结构迁移

比如一个MigrationModel的表,表中只有age和name两个字段,这个时候我们需要增加一个fullName的字段,也就是说现在MigrationModel表中变成了age,name,fullName三个字段, 这时候需要用到数据结构迁移。

原来模型

//
//  MigrationModel.h
//  realm_oc_demo
//
//  Created by allison on 2021/1/24.
//

#import <Realm/Realm.h>

NS_ASSUME_NONNULL_BEGIN

@interface MigrationModel : RLMObject

@property NSString *name;

@property int age;
@end

NS_ASSUME_NONNULL_END

创建数据库方法

- (void)viewDidLoad {
    [super viewDidLoad];

    [self setDefaultRealmForUser:@"zhangsan"];
    [self migrationAction];
}

///数据库迁移
- (void)migrationAction {
    NSLog(@"数据库路径:%@",[[RLMRealmConfiguration defaultConfiguration]fileURL]);
    MigrationModel *model = [[MigrationModel alloc]init];
    model.name = @"Allison";
    model.age = 18;
    RLMRealm *realm = [RLMRealm defaultRealm];
    [realm transactionWithBlock:^{
        [realm addObject:model];
    }];
    
}

- (void)setDefaultRealmForUser:(NSString *)userName {
    RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
    //使用默认的目录,但是使用用户名来替换默认的文件名
    config.fileURL = [[[config.fileURL URLByDeletingLastPathComponent]URLByAppendingPathComponent:userName]URLByAppendingPathExtension:@"realm"];
    //将这个配置应用到默认的realm数据库中
    [RLMRealmConfiguration setDefaultConfiguration:config];
}

此时运行demo我们发现数据结构如下所示:

01.png

新需求:增加一个fullName的字段,需要在这个表中插入一个fullName的字段,这里就数据到数据结构迁移了。

新模型

#import <Realm/Realm.h>

NS_ASSUME_NONNULL_BEGIN

@interface MigrationModel : RLMObject
//新增字段
@property NSString *fullName;

@property NSString *name;

@property int age;
@end

NS_ASSUME_NONNULL_END

此时如果直接运行,就会出现下面的报错:

02.png

*** Terminating app due to uncaught exception 'RLMException', reason: 'Migration is required due to the following errors:
这个错误的意思就是数据结构发生了变化,所以我们需要加上迁移的逻辑,并且将版本号+1(版本号默认为0),此时我们可以设置为1.

数据迁移代码如下:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.backgroundColor = [UIColor whiteColor];
    ViewController *vc = [[ViewController alloc]init];
    UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:vc];
    self.window.rootViewController = nav;
    [self migrationRealmAction];
    return YES;
}

#pragma mark -- <迁移数据库>
- (void)migrationRealmAction {

    NSLog(@"数据库路径:%@",[[RLMRealmConfiguration defaultConfiguration]fileURL]);
    //1.获取默认配置
    RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
    //2.叠加版本号(要比上一次版本号高)
    int newVersion = 1;
    config.schemaVersion = newVersion;
    //3.迁移步骤
    [config setMigrationBlock:^(RLMMigration * _Nonnull migration, uint64_t oldSchemaVersion) {
            if (oldSchemaVersion < newVersion) {
                NSLog(@"--需要迁移--oldSchemaVersion:%llu migration:%@",oldSchemaVersion,migration);
            }
    }];
    //4.让配置生效
    [RLMRealmConfiguration setDefaultConfiguration:config];
    //5.需要立即迁移
    [RLMRealm defaultRealm];
}

再次运行,数据迁移后的效果如下图所示:

03.png

至此数据结构迁移到此完成。

场景二:

刚刚情形1中的场景数据迁移仅仅需要5个步骤即可,比较简单,但是有些场景,新增的字段,是需要保留之前老字段的内容的,比如MigrationModel表中新增一个detailInfo详细信息,detailInfo = age + name + "地址信息"。

老模型

@interface MigrationModel : RLMObject
//新增字段
@property NSString *fullName;

@property NSString *name;

@property int age;
@end

新模型

@interface MigrationModel : RLMObject
//新增字段
@property NSString *detailInfo;

@property NSString *fullName;

@end

此时我们detailInfo字段的内容,要从之前的老字段age和name中获得,所以这个时候迁移的时候就需要遍历之前老的字段并取出赋值。

迁移核心代码如下所示:

#pragma mark -- <迁移数据库>
- (void)migrationRealmAction {

    NSLog(@"数据库路径:%@",[[RLMRealmConfiguration defaultConfiguration]fileURL]);
    //1.获取默认配置
    RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
    //2.叠加版本号(要比上一次版本号高)
    int newVersion = 5;
    config.schemaVersion = newVersion;
    //3.迁移步骤
    [config setMigrationBlock:^(RLMMigration * _Nonnull migration, uint64_t oldSchemaVersion) {
            if (oldSchemaVersion < newVersion) {
                NSLog(@"--需要迁移--oldSchemaVersion:%llu migration:%@",oldSchemaVersion,migration);
                [migration enumerateObjects:@"MigrationModel" block:^(RLMObject * _Nullable oldObject, RLMObject * _Nullable newObject) {
                    newObject[@"detailInfo"] = [NSString stringWithFormat:@"%@ %@ 详细地址XXX ",oldObject[@"age"],oldObject[@"name"]];
                }];
            }
    }];
    //4.让配置生效
    [RLMRealmConfiguration setDefaultConfiguration:config];
    //5.需要立即迁移
    [RLMRealm defaultRealm];

}

效果如图4所示

04.png
场景三:重命名字段

重命名字段与【场景2】类似,不再赘述。

场景四:多版本增量迁移

指的是原来我APP中有1.0的数据库,我现在需要升级到2.0。这里升级还是类似场景2,只不过需要判断版本的型号,分开来处理即可。

例:
版本0 有三个字段

@interface MigrationModel : RLMObject
@property NSString *firstName;//姓氏
@property NSString *lastName;//名字
@property int age;
@end

版本1 有2个字段
fullName = firstName + lastName

@interface MigrationModel : RLMObject
@property NSString *fullName;//新增字段
@property int age;
@end

版本2也 有2个字段

@interface MigrationModel : RLMObject
@property NSString *email;//新增字段
@property int age;
@end

问:此时如何做迁移
以下是多版本迁移的核心代码

//3.迁移步骤
   [config setMigrationBlock:^(RLMMigration * _Nonnull migration, uint64_t oldSchemaVersion) {
           if (oldSchemaVersion < newVersion) {
               if (oldSchemaVersion < 1) {
                   [migration enumerateObjects:@"MigrationModel" block:^(RLMObject * _Nullable oldObject, RLMObject * _Nullable newObject) {
                       newObject[@"detailInfo"] = [NSString stringWithFormat:@"%@ %@",oldObject[@"age"],oldObject[@"name"]];
                   }];
               }
               if (oldSchemaVersion < 2) {
                   [migration enumerateObjects:@"MigrationModel" block:^(RLMObject * _Nullable oldObject, RLMObject * _Nullable newObject) {
                       newObject[@"email"] = @"xxxx";
                   }];
               }        
           }
   }];
END.
DEMO下载
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值