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;
}
相關文章
- OCM實驗-使用線上重定義方式遷移表
- awk基礎05-自定義函式和指令碼函式指令碼
- 建立資料庫遷移資料庫
- [2]自定義Lua解析方式
- 建立自定義專案模板
- 建立自定義標籤庫
- MySQL建立自定義函式MySql函式
- 自定義例外 + 建立檢視
- 使用prebuilt table 方式遷移資料UI
- UnrealEngine建立自定義資產型別Unreal型別
- C#建立自定義配置節C#
- 使用「即刻」APP建立自定義提醒APP
- ModernUI教程:建立自定義主題UI
- 【譯】移動應用開發:如何建立自定義Android程式碼模板Android
- 如何自定義自己的vue-cli模板Vue
- 資料庫遷移的幾個方式資料庫
- BIEE 目錄遷移(資料夾)方式
- Hadoop自定義輸出排序方式Hadoop排序
- Request 增加自定義欄位的方式
- 【資料遷移】RMAN遷移資料庫到ASM(一)建立ASM磁碟組資料庫ASM
- Flutter 建立自定義路由過渡動畫Flutter路由動畫
- python - 建立一個自定義模組Python
- laravel 建立自定義的artisan make命令Laravel
- 建立Laravel自定義Helper輔助方法Laravel
- 巧用GenericObjectPool建立自定義物件池Object物件
- Laravel 建立自定義的 artisan make 命令Laravel
- 建立自定義塊 - 型別檢查型別
- XCode 建立自定義檔案模版XCode
- Houdini - 建立自定義的button樣式
- android:建立自定義控制元件Android控制元件
- Go語言自定義自己的SSH-ServerGoServer
- 用begin backup的方式遷移資料庫資料庫
- mongodb資料遷移2種方式比較MongoDB
- Laravel 自定義配置資訊的儲存方式Laravel
- PHP 自定義session儲存 FILE 方式類PHPSession
- Hibernate自定義產生主鍵方式
- MVC驗證05-自定義驗證規則、驗證2個屬性值不等MVC
- 兩種方式建立你自己的 Docker 基本映像Docker