IOS核心数据-查找或创建重复插入

IOS核心数据-查找或创建重复插入,ios,core-data,sync,nsmanagedobject,Ios,Core Data,Sync,Nsmanagedobject,在尝试将web服务数据与本地存储同步时,我的逻辑中缺少了一些东西,我需要您的帮助。这就是我得到的: 我有一个NSArray的nsdictionary描述每个事件对象(从web下载),我按事件id排序。然后我使用IN谓词获取本地存储,并按事件id排序。然后我尝试迭代和匹配id,如果它们匹配,我更新记录,如果它们不匹配,我将创建新的NSManagedObject。如果新下载的事件对象的eventID大于本地存储区中的最后一个eventID,则可以正常工作,但如果web服务中的eventID小于本地存

在尝试将web服务数据与本地存储同步时,我的逻辑中缺少了一些东西,我需要您的帮助。这就是我得到的:

我有一个
NSArray
nsdictionary
描述每个事件对象(从web下载),我按事件id排序。然后我使用IN谓词获取本地存储,并按事件id排序。然后我尝试迭代和匹配id,如果它们匹配,我更新记录,如果它们不匹配,我将创建新的
NSManagedObject
。如果新下载的事件对象的eventID大于本地存储区中的最后一个eventID,则可以正常工作,但如果web服务中的eventID小于本地存储区中的eventID,则它将插入所有对象,无论它们是否存在,这正是我的问题

换句话说,如果一条新记录位于排序数组的开头,它将添加所有对象,但如果它位于排序数组的末尾,它将更新除新记录之外的所有对象。我需要它来创建新的和更新旧的

下面是一些代码:

我认为我遗漏了一些东西的逻辑函数:

- (void)findOrCreateObject:(NSArray*)eventArray
{
    NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];

    //get sorted stored records
    NSArray *fetchedRecords = [self.fetchedResultsController fetchedObjects];

    //sort dictionaries
    NSSortDescriptor *aSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"id" ascending:YES];
    NSArray *downloadedRecords = [self.events sortedArrayUsingDescriptors:[NSArray arrayWithObject:aSortDescriptor]];

    NSLog(@"DOWNLOADED EVENTS = %@", downloadedRecords);

    NSLog(@"FETCHED EVENTS = %@", fetchedRecords);


    //if store is not empty we need to walk through data and add/update records, otherwise/ELSE we need to import initial data
    if (fetchedRecords.count != 0) {
        //stores has records already
        NSLog(@"FIND OR CREATE PROCESS");

        if ([downloadedRecords count] > 0) {

            NSArray *storedRecords = [self fetchEvents:eventArray withContext:context];

            NSUInteger currentIndex = 0;
            for (NSDictionary* event in downloadedRecords) {
                Event* eventObject = nil;

                if ([storedRecords count] > currentIndex) {

                    eventObject = [storedRecords objectAtIndex:currentIndex];
                }

                NSLog(@"STRING VALUE OF KEY = %@", [[eventObject valueForKey:@"eventID"]stringValue]);

                if ([[event valueForKey:@"id"] isEqualToString:[[eventObject valueForKey:@"eventID"] stringValue]]) {

                    //Update Record
                    NSLog(@"Updating Record!!!");
                    [self updateManagedObject:eventObject withRecord:event inContext:context];

                }
                else
                {
                    //New Record
                    NSLog(@"Inserting Record!!!");
                    eventObject = (Event*)[NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:context];
                    eventObject.eventID = [self makeNumberFromString:[event valueForKey:@"id"]];
                    eventObject.title = [event valueForKey:@"title"];
                    eventObject.venue = [event valueForKey:@"venue"];

                }
                 currentIndex++;
            }

        }

    }
    else
    {

        //import initial data
        NSLog(@"IMPORTING INITIAL DATA");

        for (NSDictionary* event in downloadedRecords) {

            Event *eventObject = (Event*)[NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:context];

            eventObject.eventID = [self makeNumberFromString:[event valueForKey:@"id"]];
            eventObject.title = [event valueForKey:@"title"];
            eventObject.venue = [event valueForKey:@"venue"];

        }
    }


    // Save the context.
    NSError *error = nil;
    if (![context save:&error]) {

        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    }
}
FETCHEVENTS方法:

-(NSArray*)fetchEvents:(NSArray*)eIDs withContext:(NSManagedObjectContext*)context
{

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:context];
    [fetchRequest setEntity:entity];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(eventID IN %@)", eIDs];
    [fetchRequest setPredicate:predicate];

    [fetchRequest setSortDescriptors:@[ [[NSSortDescriptor alloc] initWithKey: @"eventID" ascending:YES] ]];

    NSError *error = nil;
    NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
    if (fetchedObjects == nil) {
        NSLog(@"No rows returned");
    }

    return fetchedObjects;
}
更新对象方法:

- (void)updateManagedObject:(NSManagedObject*)object withRecord:(NSDictionary*)record inContext:(NSManagedObjectContext*)context
{
    [object setValue:[self makeNumberFromString:[record valueForKey:@"id"]] forKey:@"eventID"];
    [object setValue:[record valueForKey:@"title"] forKey:@"title"];
    [object setValue:[record valueForKey:@"venue"] forKey:@"venue"];
}
下载web服务数据并对其进行解析后,我将调用findOrCreate方法


如果您有任何其他问题,请告诉我。

我认为,每次插入新的事件对象时,您都应该更新
storedObjects
,以便它现在应该包含插入的对象。 或者更简单地说,您应该将
storedObjects
的初始化行放在for循环中。(这将确保当您从
downloadeobjects
开始枚举时,每个
eventObject
上的索引都与
storedObjects
上的索引相同。但是,对于您的代码而言,只有当
storedObjects
的所有元素总是在
downloadebjects
中找到时,这才是正确的。)嗯,我想是这样的。)

但是有一件事是不是
fetchedRecords
应该与
storedObjects
相同,如果它们是,您应该将storedObjects重新分配为
[self.fetchedResultsController fetchedObjects]
,因为它将反映您上下文中的更改,而无需执行另一个获取请求,这将解决上述建议的低效性。

试试这个

- (void)findOrCreateObject:(NSArray*)eventArray {

//if store is not empty we need to walk through data and add/update records, otherwise/ELSE we need to import initial data
    if (fetchedRecords.count != 0) {
        //stores has records already
        NSLog(@"FIND OR CREATE PROCESS");

        if ([downloadedRecords count] > 0) {

            NSArray *storedRecords = [self fetchEvents:eventArray withContext:context];
            for (NSDictionary* event in downloadedRecords) {
                NSPredicate *predicate = [NSPredicate predicateWithFormat:@"eventID = %@",[event valueForKey:@"id"]];
                NSArray *matchedArray = [storedRecords filteredArrayUsing
Predicate:predicate]; 
                Event* eventObject = nil;
                if ([matchedArray count] > 0) {

                    //Update Record
                    NSLog(@"Updating Record!!!");
                    eventObject = [matchedArray objectAtIndex:0];
                    [self updateManagedObject:eventObject withRecord:event inContext:context];

                }
                else
                {
                    //New Record
                    NSLog(@"Inserting Record!!!");
                    eventObject = (Event*)[NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:context];
                    eventObject.eventID = [self makeNumberFromString:[event valueForKey:@"id"]];
                    eventObject.title = [event valueForKey:@"title"];
                    eventObject.venue = [event valueForKey:@"venue"];

                }
            }
        }
    } else {
        .....
    }
}

请进行更多的调试并编辑您的问题,以专门涵盖工作不正常的部分。工作正常。起初它对我不起作用,因为我的eventID是NSNumber,所以我总是得到空的匹配数组。我修好了,它成功了。谢谢,这意味着我将不得不对下载的数组中的每个对象进行提取,这是我不想做的。如果在一个数组中有数千个对象,那么它的效率很低,而且成本也很高。是的,这个答案非常简单。除了建议使用fetchresultscontroller之外,您还可以为storedObjects使用NSMutableArray,并在其中插入当前索引中新创建的eventObject,这不会影响此示例代码的效率