12

我有一个允许用户保存收藏夹的应用程序。我正在使用 Core Data 将收藏夹存储为托管对象。我已经编写了一些代码来防止存储重复项的可能性,但我想知道是否有更好的方法来做到这一点。每个收藏对象都有一个唯一的 ID 字段。在下面的代码中,我只是循环并检查 ID 字段,如果该值已经存在,则将标志值设置为 true,然后跳出循环。

-(BOOL)addFavorite{
    BOOL entityExists = NO;
    if(context){
        // does this favorite already exist?
        NSArray *allFaves = [AppDataAccess getAllFavorites];
        for(Favorite *f in allFaves){
            if([f.stationIdentifier isEqualToString:stID]){
                entityExists = YES;
                break;
            }
        }
        if(!entityExists){
            NSError *err = nil;
            Favorite *fave = [Favorite insertInManagedObjectContext:context];
            fave.stationRealName = riverGauge.name;
            fave.stationIdentifier = stID;
            fave.stationState = @"WV";
            if(![context save:&err]){
                NSLog(@"ERROR: Could not save context--%@", err);
            }
            return YES;            
        }
    return NO;
}

我想知道 Core Data 是否有能力检查添加的对象是否重复。是否有可以处理重复检查的谓词?谢谢!

4

6 回答 6

23

CoreData 本身并没有唯一性。它没有两个条目相同的概念。

要启用这种行为,您必须自己通过“插入前搜索”或“创建前获取”来实现它。

NSFetchRequest *fetch = [NSFetchRequest fetchRequestWithEntityName:@"Favorite"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"stationIdentifier == %@", stID];
[fetch setPredicate:predicate];
YourObject *obj = [ctx executeRequest:fetch];

if(!obj) {
    //not there so create it and save
    obj = [ctx insertNewManagedObjectForEntity:@"Favorite"]; //typed inline, dont know actual method
    obj.stationIdentifier = stID;
    [ctx save];
}

//use obj... e.g.
NSLog(@"%@", obj.stationIdentifier);

请记住,这假设单线程访问

于 2013-08-15T22:49:29.377 回答
10

只是自 iOS 9.0 以来的更新,您可以使用模型中的“唯一约束”轻松完成。但请注意 - 如果您的商店已经包含重复项,则核心数据将在应用程序发布时无法进行任何自动迁移。

例如,请参见此处 -核心数据唯一约束

于 2016-09-15T10:46:21.640 回答
5

斯威夫特 3

func isExist(id: Int) -> Bool {
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: myEntityName)
    fetchRequest.predicate = NSPredicate(format: "id = %d", argumentArray: id)

    let res = try! theContext.fetch(fetchRequest)
    return res.count > 0 ? true : false
}
于 2017-04-25T16:36:21.637 回答
5

Swift 4 Curled from @Vahid 回答

func isEntityAttributeExist(id: Int, entityName: String) -> Bool {
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let managedContext = appDelegate.persistentContainer.viewContext
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
    fetchRequest.predicate = NSPredicate(format: "id == %@", id)
    let res = try! managedContext.fetch(fetchRequest)
    return res.count > 0 ? true : false
}
于 2019-02-15T12:22:17.193 回答
4

我想知道 Core Data 是否有能力检查添加的对象是否重复。

不,Core Data 不关心这个。

是否有可以处理重复检查的谓词?

由于您的对象具有您控制的唯一 ID,因此请使用该 ID 获取现有收藏夹。就像是

NSFetchRequest *fetch = [NSFetchRequest fetchRequestWithEntityName:@"Favorite"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"stationIdentifier == %@", stID];
[fetch setPredicate:predicate];

如果您得到任何结果,您就知道具有该 ID 的收藏夹已经存在。而且,如果您想更改它,您可以参考该收藏夹。

如果只有几个收藏夹,您当前的方法很好,并且可能更快。进行抓取将更好地扩展到许多收藏夹。

于 2013-08-15T21:31:52.787 回答
3

如果您正在处理多条记录,则迭代计数获取或检索实际对象在 CPU 上的成本非常高。就我而言,我对所有匹配的记录进行了一次提取,但要求提供一个仅包含 UUID 字符串的字典。节省了大量的 CPU 开销。

例如,我在核心数据的每条记录上都有一个 uUID 属性。我在 CloudKit 中有一个相应的 UUID 列为@“UUID”。

  //1. Create a request for the entity type, returning an array of dictionaries  
      NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:@"someEntityName"];
      [request setResultType:NSDictionaryResultType];
      [request setReturnsDistinctResults:YES];
      [request setPropertiesToFetch: @[@"uUID"]];

  //2. Create an array of UUID strings of the downloaded objects
      NSMutableArray *UUIDstrings = [NSMutableArray new];
      for (CKRecord *record in ckRecords) {
        [UUIDstrings addObject:record[@"UUID"]];
      }

   //3. Create a predicate to find any Core Data objects with the same UUID
      [request setPredicate:[NSPredicate predicateWithFormat:@"uUID in %@", UUIDstrings]];

   //4. If there are results from the fetch, do a log and you'll see it's a dictionary. 
      NSArray *deck = [self.MOC executeFetchRequest:request error:nil];

      NSLog(@"Logging the result of index 0. Should be a dictionary %@", deck.count > 0 ? [deck objectAtIndex:0] : @"No results");

   //5. Then either do an embedded fast enumeration (for xx in xx){for xx in xx} to find a match like         

           if ([(NSString *)record[@"UUID"] isEqualToString:[dict valueForKey:@"uUID"]]) 
          {do something}

   //...Or 6. Use a more linear approach with NSSet

    //Harvest the core data strings
      NSMutableArray *coreDataStrings = [NSMutableArray new];
        for (NSDictionary *dict in deck) {
        [coreDataStrings addObject:[dict objectForKey:@"uUID"]];
      }

   //Create a set of your downloaded objects
      NSSet *arraySet = [NSSet setWithArray:ckRecords];

   //Then use a predicate search - a NOT version of above
     NSArray *final = [[arraySet filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"NOT(UUID in %@)", coreDataStrings]]allObjects];

字典的控制台日志看起来像这样。匹配所需的最少信息量:

dictionary {
   uUID = "AFACB8CE-B29E-4A03-9284-4BD5F5464";
}

在开发者网站上找到更多关于寻找独特价值的信息。

于 2017-01-05T10:47:56.630 回答