05-自己建立mapmodel自定義遷移方式
自動建立Mapping
如果模型的改變很大或者不支援輕量級資料遷移的條件,則我們需要進行自定義遷移。
使用對映模型 適用於更加複雜的資料的遷移
NSMappingModel
類似於資料模型
NSEntityMapping
告知遷移過程如何在目標資料儲存中處理源實體的對映。
對映型別決定了如何處理目標資料儲存中的特定實體。對映型別有新增 移除 複製 變換。
- 新增對映:一個目標中的新實體新增到目標資料儲存中
- 移除對映:實體不存在目標對映中,只存在於源中。
- 複製對映:將源物件完全相同地複製到目標
- 變換對映: 實體存在於源和目標中並且對映應該以某種方式將源變換到目標。
NSPropertyMapping
告知遷移過程如何將源屬性對映到目標屬性。
在從源資料儲存到目標資料儲存移動資料是可以提供一個值表示式來轉換值。
開始一個自定義的遷移方式
1 新建一個mapModel
- 確保Data Model 處於選中狀態
- File > New > File> iOS > Core Data > Mapping Model , 並點選Next 按鈕
- 將舊版本的設定為Source Data Model 並點選Next 按鈕 ,將新建的設定為Target Data Model, 並點選Next 按鈕
- 儲存mappingModel
2 程式碼的實現
首先要判斷本地資料庫檔案和當前使用資料模型的結構是否相同。
如果不相同的話進行遷移。
1 在開啟本地資料庫的時候就要進行判斷
// 判斷是否需要遷移 是否已經遷移過了
- (BOOL)isHaveMigration
{
// 原來的資料庫路徑 不存在直接進行返回
NSString *docStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *sqlPath = [docStr stringByAppendingPathComponent:@"student.sqlite"];
NSURL *sqlURL = [NSURL fileURLWithPath:sqlPath];
if (![[NSFileManager defaultManager] fileExistsAtPath:sqlPath]) {
return NO;
}
// 比較存在模型資料的後設資料
NSError *error = nil;
// 資料庫的資料結構
NSDictionary *sourceMetaData = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:sqlURL options:nil error:&error];
// 比較資料庫的資料 和目標資料是否相同 如果相同 不需要遷移操作
NSManagedObjectModel *destinationModel = _coord.managedObjectModel;
if ([destinationModel isConfiguration:nil compatibleWithStoreMetadata:sourceMetaData]) {
return NO;
}
return YES;
}
2 如果需要遷移 則進行遷移操作
- (BOOL)startMigration
{
BOOL success = NO;
NSError *error = nil;
// 舊的資料庫路徑
NSString *docStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *sqlPath = [docStr stringByAppendingPathComponent:@"student.sqlite"];
NSURL *sqlURL = [NSURL fileURLWithPath:sqlPath];
// 原來的資料模型資訊
NSDictionary *sourceMetaData = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:sqlURL options:nil error:&error];
// 原來的資料模型
NSManagedObjectModel *soureceModel = [NSManagedObjectModel mergedModelFromBundles:nil forStoreMetadata:sourceMetaData];
// 當前的資料模型資訊
NSManagedObjectModel *destinationModel = _coord.managedObjectModel;
// 載入資料遷移的模型 mappingModel
NSMappingModel *mapModel = [NSMappingModel mappingModelFromBundles:nil forSourceModel:soureceModel destinationModel:destinationModel];
if (mapModel) {
// 遷移管理器
NSMigrationManager *mgr = [[NSMigrationManager alloc]initWithSourceModel:soureceModel destinationModel:destinationModel];
// 監聽的資料遷移的進度
// 監聽的進度可以用來給使用者進行展示 例如說QQ新版本更新完之後開啟之後,有一個進度條會更新資料,應該就是這個操作
[mgr addObserver:self
forKeyPath:@"migrationProgress"
options:NSKeyValueObservingOptionNew
context:NULL];
// 先把模型儲存到臨時的sqlite 遷移完成再進行替換操作
// 目的路徑
NSString *destPath = [docStr stringByAppendingPathComponent:@"temp2.sqlite"];
NSURL *destURL = [NSURL fileURLWithPath:destPath];
success = [mgr migrateStoreFromURL:sqlURL type:NSSQLiteStoreType options:nil withMappingModel:mapModel toDestinationURL:destURL destinationType:NSSQLiteStoreType destinationOptions:nil error:&error];
if (success) {
// 證明資料遷移成功
[self replaceStore:sqlURL withStore:destURL];
}else{
// 遷移資料失敗
NSLog(@"%@",error.description);
}
}
return success;
}
// 響應監聽的方法
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if ([keyPath isEqualToString:@"migrationProgress"]) {
dispatch_async(dispatch_get_main_queue(), ^{
float progress =
[[change objectForKey:NSKeyValueChangeNewKey] floatValue];
int percentage = progress * 100;
NSString *string =
[NSString stringWithFormat:@"Migration Progress: %i%%",
percentage];
NSLog(@"%@",string);
});
}
}
// 將舊的移除新的放置在舊的上面
-(BOOL)replaceStore:(NSURL *)old withStore:(NSURL *)new
{
BOOL success = NO;
NSError *error = nil;
if ([[NSFileManager defaultManager] removeItemAtURL:old error:&error]) {
error = nil;
if ([[NSFileManager defaultManager] moveItemAtURL:new toURL:old error:&error]) {
success = YES;
}
}
return success;
}
相關文章
- awk基礎05-自定義函式和指令碼函式指令碼
- [2]自定義Lua解析方式
- 建立自定義專案模板
- Hadoop自定義輸出排序方式Hadoop排序
- 巧用GenericObjectPool建立自定義物件池Object物件
- [譯] 從 0 建立自定義元素
- WWDC 2018:建立自定義的 Instrument
- XCode 建立自定義檔案模版XCode
- 容器和映象轉化、遷移方式【轉】
- 如何自定義自己的vue-cli模板Vue
- Request 增加自定義欄位的方式
- springbootredis自定義序列化方式(fastJson)Spring BootRedisASTJSON
- 自定義元件-元件的建立和引用元件
- UnrealEngine建立自定義資產型別Unreal型別
- python - 建立一個自定義模組Python
- 建立Laravel自定義Helper輔助方法Laravel
- matlab自定義函式建立與使用Matlab函式
- laravel 建立自定義的artisan make命令Laravel
- Houdini - 建立自定義的button樣式
- Laravel 建立自定義的 artisan make 命令Laravel
- mongodb資料遷移2種方式比較MongoDB
- 利用offline datafile檔案方式遷移資料
- 用begin backup的方式遷移資料庫資料庫
- 建立遷移檔案 auth 認證表 users
- Go語言自定義自己的SSH-ServerGoServer
- 網站遷移紀實:從Web Form 到 Asp.Net Core (Abp vNext 自定義開發)網站WebORMASP.NET
- Laravel Admin 自定義 JavaScript 的正確方式?LaravelJavaScript
- PHP 自定義session儲存 FILE 方式類PHPSession
- gym建立環境、自定義gym環境
- Flutter 建立自定義路由過渡動畫Flutter路由動畫
- Hive--->建立自定義的UDTF函式Hive函式
- RN自定義元件封裝 - 神奇移動元件封裝
- 1.0 ORACLE到MYSQL資料遷移方式選型OracleMySql
- Laravel 通過遷移指令碼建立MySQL檢視Laravel指令碼MySql
- Laravel 透過遷移指令碼建立MySQL檢視Laravel指令碼MySql
- 【朝花夕拾】Android自定義View篇之(四)自定義View的三種實現方式及自定義屬性詳解AndroidView
- Laravel 自定義配置資訊的儲存方式Laravel
- 在 React 中建立自定義 Hook 的最佳技巧ReactHook