在创build新对象时查询特定属性的核心数据,如果存在,则返回该对象;如果不存在,则创build一个新的对象

我有一个问题,在创build一个新对象之前,通过谓词检查一个实体的特定属性是否存在于核心数据库中; 如果对象存在,我宁愿返回它比创build一个新的对象。

我有一个简单的应用程序,在导航栏中有一个带有加号button的表格视图; 用户点击它,并带有4个文本字段的视图控制器。 他们填写这些信息,按保存,它被保存到核心数据,并显示在TableView中(通过使用NSFetchedResultsControllers)。

数据模型如下:

具有isReceived的事务实体BOOL属性具有名称string属性的Person实体具有标题string属性的Occasion实体具有数量string属性的Item实体

交易与Person(whoBy),Occasion(Occasion)和Item实体有关系。

在具有save方法的视图控制器中,我有下面的代码将新的对象插入交易,人员,场合实体等。每个交易当然是唯一的,但是对于每个交易,用户可以select现有的PERSON /或场合,如果那个人不存在,它将被创build(同样的情况下)。

我对这里的代码格式略有困惑。

编辑:我已经尝试了代码的组合,可以只是不能得到这个工作。 在下面的代码中,我在谓词中引用person.name,但是我也尝试创build一个本地的NSStringvariables来保存self.nameTextField.text代码,但是什么也没做。 我试图创build一个NSString属性来引用它的方式,这是行不通的。 我试着用MATCHES, LIKE, CONTAINS, ==和每个组合之间的单词。

 - (IBAction)save:(id)sender { NSManagedObjectContext *context = [self managedObjectContext]; Transaction *transaction= [NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:context]; Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context]; Occasion *occasion = [NSEntityDescription insertNewObjectForEntityForName:@"Occasion" inManagedObjectContext:context]; Item *amount = [NSEntityDescription insertNewObjectForEntityForName:@"item" inManagedObjectContext:context]; NSFetchRequest *personFind = [NSFetchRequest fetchRequestWithEntityName:@"Person"]; personFind.predicate = [NSPredicate predicateWithFormat:@"name == %@", person.name]; // I have tried every combination of the predicate like MATCHES, LIKE. // I created a local NSString variable and an NSString property NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]; personFind.sortDescriptors = [NSArray arrayWithObject:sortDescriptor]; NSError *error = nil; NSArray *matches = [context executeFetchRequest:personFind error:&error]; if (!matches || ([matches count] > 1)) { // Handle Error } else if ([matches count] == 0) { person.name = self.nameTextField.text; transaction.whoBy = person; occasion.title = self.occasionTextField.text; transaction.occasion = occasion; } else { person = [matches lastObject]; transaction.whoBy = person; occasion.title = self.occasionTextField.text transaction.occasion = occasion; } if (![context save:&error]) { NSLog(@"Can't save! %@ %@", error, [error localizedDescription]); } [self dismissViewControllerAnimated:YES completion:nil]; 

}

从逻辑上讲,我想达到的是:

  • 当用户添加一个事务时,检查是否是一个新的人或一个现有的人 – 如果它是一个现有的人,从人员列表中select它(当用户select一个人,得到它的NSManagedObjectID)。 如果是新的,就当场创build。

  • 同样的场合。

设置交易对象的所有其他字段(金额等)。

我的问题是:

  • 我用什么谓词来实现这个function?

当我在这个方法中放置一个断点时,一个NEW NAME(以前不存在的)正确调用else if ([matches count] == 0)方法,如果我创build一个具有现有名称的条目,它会调用该

 else { person = [matches lastObject]; transaction.whoBy = person; occasion.title = self.occasionTextField.text transaction.occasion = occasion; } 

即使有了这个声明,它仍然为同一个名字创build一个新的人物对象。

在得到这个人的工作之后,我会正确地实施这个机会,但是我只是为了得到这个工作而迷失了方向。

任何帮助将大力赞赏!

“它是否正确?”:
不,您正在创build一个新的PersonOccasion对象,无论您是否使用现有的人物/场合。
首先检查是否存在,只有当对象不存在时才插入一个新的。
或者,如果个人/场合存在,则删除插入的对象。

“如何检索person / event的managedObjectID?”:

 Person* person = /*Get an existing person object*/ NSManagedObjectID* personId = person.objectID /*This is the person object ID, will work for any NSManagedObject subclass*/ 

要查找以stringstr开头的人员,请在获取请求中使用此谓词:

 /*UNTESTED*/ [NSPredicate predicateWithFormat:@"(name BEGINSWITH[cd] %@)", str]; 

编辑:

更确切地说,你练习使用这样的东西来查找或创build:
(这是非常有限的,只有一个单一的对象性能明智)(未testing

 - (NSManagedObject*) findOrCreateObjectByValue:(id)value propertyName:(NSString*)propertyName entityName:(NSString*)entityName additionalInfo:(NSDictionary*)additionalInfo context:(NSManagedObjectContext*)context error:(NSError* __autoreleasing*)error { NSManagedObject* res = nil; NSFetchRequest* r = [NSFetchRequest fetchRequestWithEntityName:entityName]; [r setPredicate:[NSPredicate predicateWithFormat:@"%K == %@",propertyName,value]]; NSArray* matched = [context executeFetchRequest:r error:error]; if (matched) { if ([matched count] < 2) { res = [matched lastObject]; if (!res) { //No existing objects found, create one res = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context]; [res setValue:value forKey:propertyName]; [res setValuesForKeysWithDictionary:additionalInfo]; } } else { if (error) { *error = [NSError errorWithDomain:@"some_domain" code:9999 userInfo:@{@"description" : @"duplicates found"}]; } } } return res; } 

所以现在,你的save:方法应该是这样的:
(我在这里假设人物名称和场合标题由视图控制器上的UITextField分别保存[ txtPersonNametxtOccasionTitle ])

 - (void) save:(id)sender { //create a clean context so that changes could be discarded automatically on failure NSManagedObjectContext* context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; [context setParentContext:[self managedObjectContext]]; //A Transaction is always created in save event, so add it to the context Transaction* transaction = [NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:context]; __block NSError* error = nil; Person* p = (Person*)[self findOrCreateObjectByValue:self.txtPersonName.text propertyName:@"name" entityName:@"Person" additionalInfo:nil context:context error:&error]; if (!p) { NSLog(@"Error: %@, person name: %@",error,self.txtPersonName.text); return; } Occasion* o = (Occasion*)[self findOrCreateObjectByValue:self.txtOccasionTitle.text propertyName:@"title" entityName:@"Occasion" additionalInfo:nil context:context error:&error]; if (!o) { NSLog(@"Error: %@, occasion title: %@",error,self.txtOccasionTitle.text); return; } transaction.whoBy = p; transaction.occasion = o; //Not sure what you are using this property for transaction.item = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:context]; NSManagedObjectContext* ctx = context; if ([context obtainPermanentIDsForObjects:[context.insertedObjects allObjects] error:&error]) { //save your changes to the store __block BOOL saveSuccess = YES; while (ctx && saveSuccess) { [ctx performBlockAndWait:^{ saveSuccess = [ctx save:&error]; }]; ctx = [ctx parentContext]; } if (!saveSuccess) { NSLog(@"Could not save transaction, error: %@",error); } } else { NSLog(@"Could not obtain IDs for inserted objects, error: %@",error); } //Do what you have to do next } 

这只是为了使你的工作更清楚一些,避免重复,重复使用现有的对象。