xcode 处理核心数据中的重复条目

mznpcxlj  于 2023-03-13  发布在  其他
关注(0)|答案(6)|浏览(147)

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

-(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是否有能力检查正在添加的对象是否是重复的。有没有 predicate 可以处理重复检查?谢谢!

lymgl2op

lymgl2op1#

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);

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

izj3ouym

izj3ouym2#

只要是iOS 9.0之后的更新,您就可以通过模型中的“唯一约束”轻松完成。但请注意-如果您的商店已经包含重复数据,则在应用发布时,核心数据将无法进行任何自动迁移。
例如,请参见此处-core data unique constraints

zyfwsgd6

zyfwsgd63#

雨燕4

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
}
frebpwbc

frebpwbc4#

雨燕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
}
nhjlsmyf

nhjlsmyf5#

我想知道Core Data是否有能力检查正在添加的对象是否是重复的。
不,核心数据不关心这个。
是否有一个 predicate 可以处理重复检查?
由于对象具有唯一的ID,可以由您控制,因此可以获取具有该ID的现有收藏夹。

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

如果您得到任何结果,您就知 prop 有该ID的收藏夹已经存在。并且,如果您想更改它,您可以引用该收藏夹。
如果只有几个收藏夹,您当前的方法是很好的,而且可能更快。执行获取将更好地扩展到许多收藏夹。

lb3vh1jj

lb3vh1jj6#

如果你要处理多个记录,那么遍历一个计数获取或者检索实际的对象在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";
}

More here at the developer site表示查找唯一值。

相关问题