Reputation: 1931
I have an entity in Core Data which has an attribute that needs to be unique. There's no way to set this in the visual interface. I assume I need to create a custom class that inherits from NSManagedObject and then write my own validation method.
I successfully created the custom class by selecting the entities in the visual editor and choosing File -> New -> New File -> NSManagedObject subclass. I use this to add creation timestamps, so I know it works.
But now what? Which methods do I need?
The NSManagedObject reference guide tells me to "implement methods of the form validate:error:" but doesn't provide an example.
Similar questions here and here, but I need a bit more help.
A complete example would be awesome, but any help is much appreciated.
Upvotes: 8
Views: 3746
Reputation: 1464
validateValue
mentioned below will do the validation trick (and correct place to make validation)
If you use NSFetchedResultsController
, however, don't forget to remove object from memory to avoid duplicate object in UITableView
even on failure.
Something like this:
CustomManagedObject *obj = [NSEntityDescription insertNewObjectForEntityForName:@"<YourEntity>" inManagedObjectContext:self.managedObjectContext];
obj.property = @"some property";
if (![self.managedObjectContext save:&error]) {
[self.managedObjectContext deleteObject:obj]; // delete from memory. Otherwise, you get duplicated value in UITableView even if save has failed
}
Upvotes: 2
Reputation: 21254
Let's say you have a property foo
that you want to validate
From Property-Level Validation :
If you want to implement logic in addition to the constraints you provide in the managed object model, you should not override
validateValue:forKey:error:
. Instead you should implement methods of the formvalidate<Key>:error:
.
Where <Key>
is your property. You would actually implement something like:
-(BOOL)validateFoo:(id *)ioValue error:(NSError **)outError {
return [self isUnique];
}
Upvotes: 6
Reputation: 1931
This does the trick, although it is slow on bulk inserts and you still need to create an NSError object.
-(BOOL)validateValue:(__autoreleasing id *)value forKey:(NSString *)key error:(NSError *__autoreleasing *)error {
[super validateValue:value forKey:key error:error];
// Validate uniqueness of my_unique_id
if([key isEqualToString:@"my_unique_id"]) {
NSFetchRequest * fetch = [[NSFetchRequest alloc] init];
[fetch setEntity:[NSEntityDescription entityForName:[self.entity name]
inManagedObjectContext:self.managedObjectContext]];
NSPredicate *predicate = [NSPredicate
predicateWithFormat:@"my_unique_id = %@",[self valueForKey:key]];
fetch.predicate = predicate;
NSError *error = nil;
NSUInteger count = [self.managedObjectContext
countForFetchRequest:fetch error:&error];
if (count > 1) {
// Produce error message...
// Failed validation:
return NO;
}
}
return YES;
}
Upvotes: 1