本文介绍了如何在轻量级迁移后从Core Data中删除数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在将我的应用程序从v1升级到v2时,我对Core数据模型进行了一些小的更改。更改只是为模型添加新属性。



我对版本化的数据模型与之前和之后的更改,并在我的应用程序代理中实现以下代码:

   - (NSPersistentStoreCoordinator *)persistentStoreCoordinator 
{
if(__persistentStoreCoordinator!= nil)
{
return __persistentStoreCoordinator;
}

NSURL * storeURL = [[self applicationDocumentsDirectory] ​​URLByAppendingPathComponent:@ISDEmployees.sqlite];

NSLog(@storeURL:%@,storeURL);

NSError * error = nil;

//为自动轻量级核心数据迁移创建字典
NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES],NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES],NSInferMappingModelAutomaticallyOption,
nil];

__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

//设置持久存储并根据需要迁移
if(![__ persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:& error])
{
NSLog(@未解析的错误%@,%@,错误,[错误userInfo]);
abort();
}

return __persistentStoreCoordinator;
}

基本上添加了迁移选项的标准persistentStoreCoordinator。此代码工作正常,我的数据库已成功更新。我遇到的问题是,在数据库更新后,我需要刷新数据库中的所有数据,以便新的列填充。我想我会删除相关实体/表中的数据,并强制应用程序重新下载一个新的数据集与添加的列/属性。



m不知道如何/在哪里执行删除/更新。一般的应用程序流程是:




  • 使用网络API进行验证登录

  • 登录,调用API并获取最新添加/更新的记录。

  • 显示更新的数据



我知道我可以通过将此代码添加到persistentStoreCoordinator来检查是否需要迁移:

  //获取当前数据存储元数据
BOOL migrationNeeded = NO;
NSDictionary * existingStoreData = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:storeURL error:& error];

if(existingStoreData)
{
//检查新模型是否与现有模式不一样,这意味着需要迁移
if(! [self.managedObjectModel isConfiguration:nil compatibleWithStoreMetadata:existingStoreData])
{
migrationNeeded = YES;
}
}

任何帮助将非常感谢! >

更新#1:



根据以下反馈,更改:



已将AppDelegate上的migrationNeeded从本地更改为公共类变量。
在登录视图中,我添加了以下方法:

   - (void)checkForDatabaseMigration 
{
//获取受管对象上下文的副本。如果需要迁移,它会将其关闭
NSManagedObjectContext * managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];

if([(AppDelegate *)[[UIApplication sharedApplication] delegate] migrationNeeded])
{
//从表中删除所有数据
}

managedObjectContext = nil;
}

看起来不错吗?代码工作,迁移后删除数据,插入一个新的副本。

解决方案

如果您知道如何确定何时删除旧数据,所有你需要的是获取所有你需要的和删除它们。以下是您的操作方式(例如,如果您要删除所有品种):

  NSFetchRequest * request = [[NSFetchRequest alloc] init]; 
[request setEntity:[NSEntityDescription entityForName:@ManinManagedObjectContext:myContext]];
[request setIncludesPropertyValues:NO]; //只获取managedObjectID

NSError * error = nil;
NSArray * men = [myContext executeFetchRequest:request error:& error];
//错误处理在这里
for(NSManagedObject * man in men){
[myContext deleteObject:man];
}
NSError * saveError = nil;
[myContext save:& saveError];
//更多错误处理在这里


In upgrading my application from v1 to v2, I've made a few small changes to the Core Data Model. The changes are just adding new attributes to the models.

I have versioned the data model with the before and after changes and implemented the following code in my App Delegate:

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (__persistentStoreCoordinator != nil)
    {
        return __persistentStoreCoordinator;
    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"ISDEmployees.sqlite"];

    NSLog(@"storeURL:%@",storeURL);

    NSError *error = nil;

    // Create a dictionary for automatic lightweight core data migration
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
                             nil];

    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

    // Set up the persistent store and migrate if needed
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
    {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return __persistentStoreCoordinator;
}

Basically the standard persistentStoreCoordinator with the addition of the migration options. This code works great and my database is successfully updated. The problem that I'm having is that after the database update, I need to refresh all of the data in the database so that the new columns are populated. I was thinking that I would delete the data from the relevant entities/tables and force the application to re-download a new dataset with the added columns/attributes.

I'm not sure how/where to perform the delete/updates. The general application flow is this:

  • Log in with validation against an web API
  • On successful login, call the API and get latest added/updated records.
  • Display the updated data

I know I can check to see if a migration is needed by adding this code to persistentStoreCoordinator:

// Get the current data store meta data
BOOL migrationNeeded = NO;
NSDictionary *existingStoreData = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:storeURL error:&error];

if (existingStoreData)
{
    // Check to see if new model is not the same as the existing mode, meaning a migration is required
    if (![self.managedObjectModel isConfiguration:nil compatibleWithStoreMetadata:existingStoreData])
    {
        migrationNeeded = YES;
    }
}

Any help would be greatly appreciated!!

Update #1:

Based on the feedback below, I've made the following changes:

Changed the migrationNeeded from a local to a public class variable on the AppDelegate.On the Login View, I've added the following method:

- (void)checkForDatabaseMigration
{
    // Get a copy of the managed object context. If a migration is needed, it will kick it off
    NSManagedObjectContext *managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];

    if ([(AppDelegate *)[[UIApplication sharedApplication] delegate] migrationNeeded])
    {
        // Delete all data from the table
    }

    managedObjectContext = nil;
}

Does that seem right? The code works and the data is removed after migration and a fresh copy is inserted. I just hate to check for migration each time the application starts.

解决方案

If you know how to determine when to delete old data, all you need is to fetch all the enteties you need and delete them. Here is how you do that(for example, if you want to delete all Man enteties):

    NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"Man" inManagedObjectContext:myContext]];
[request setIncludesPropertyValues:NO]; //only fetch the managedObjectID

NSError * error = nil;
NSArray * men = [myContext executeFetchRequest:request error:&error];
//error handling goes here
for (NSManagedObject * man in men) {
  [myContext deleteObject:man];
}
NSError *saveError = nil;
[myContext save:&saveError];
//more error handling here

这篇关于如何在轻量级迁移后从Core Data中删除数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-30 03:01