Reputation: 11319
A common scenario for core data driven apps is getting a unique object out of the backing store. If the object with a certain unique property exists, return that one, if it doesn't return a newly create one. I found myself writing the same thing over and over, so I wrapped it in a convenience method. But this seems so trivial, am I reinventing the wheel here? Is there a simpler, out-of-the-box way to achieve this?
Cheers,
EP
+(id)uniqueEntityfForName:(NSString *)name
withValue:(id)value
forKey:(NSString *)key
inManagedObjectContext:(NSManagedObjectContext *)context {
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
request.entity = [NSEntityDescription entityForName:name inManagedObjectContext:context];
request.predicate = [NSPredicate predicateWithFormat:[key stringByAppendingString:@" == %@"], value];
NSArray *result = [context executeFetchRequest:request error:nil];
id entity = [result lastObject];
if (entity == nil) {
entity = [NSEntityDescription insertNewObjectForEntityForName:name inManagedObjectContext:context];
[entity setValue:value forKey:key];
} else {
entity = [result lastObject];
}
return entity;
}
I use this method like this:
SomeEntity *entity = [CDUtils uniqueEntityfForName:@"SomeEntity" withValue:@"foo" forKey:@"bar" inManagedObjectContext:context];
Upvotes: 13
Views: 4864
Reputation: 1125
A more flexible solution is to use Blocks
to let the caller to handle 3 situations when comparing two lists.
Therefore, there is no need to create similar functions when inserting in a syncing fashion or additions to the data store.
typedef void (^objectOperationBlock)(NSManagedObjectContext *context,
NSDictionary *hostObjectData,
NSManagedObject *localManagedObject);
- (void) insertUniquely:(NSArray *)rawDataArray
entity:(NSString *)entity
matchedBlock:(objectOperationBlock)matchedOperation
hostUnmatchedBlock:(objectOperationBlock)hostUnmatchedOperation
localUnmatchedBlock:(objectOperationBlock)localUnmatchedOperation
error:(NSError **)outError;
A full implementation can be found here: http://emplementation.blogspot.com/2011/12/importing-data-into-core-data-while.html
Upvotes: 2
Reputation: 7327
Pretty standard. My core data entities have lots of methods like [aStudent enrollmentForId:(long long)idValue createIfMissing:YES]
.
I'd also like to plug mogenerator , which removes much pain from Core Data. Among other things, it generates a factory method for every fetch request defined in the data model. So making a fetch predicate in the model like, e.g,
thingies:
thingyId == $forThingyId
yields a matching class method:
+(NSArray *)fetchThingies:(NSManagedObjectContext *)moc forThingyId:(id)thingyId
...which does the first half of what you've written up there. A wrapper like
-(Thingy*)thingyForIdValue:(long long)thingyId
is then trivial to write, in whatever class holds your managedObjectContext (eg. a "parent" entity, or app delegate, or whatever.)
Upvotes: 3