Core Data unique attributes
Solution 1:
Every time i create on object I perform a class method that makes a new Entity only when another one does not exist.
+ (TZUser *)userWithUniqueUserId:(NSString *)uniqueUserId inManagedObjectContext:(NSManagedObjectContext *)context
{
TZUser *user = nil;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:@"TZUser" inManagedObjectContext:context];
request.predicate = [NSPredicate predicateWithFormat:@"objectId = %@", uniqueUserId];
NSError *executeFetchError = nil;
user = [[context executeFetchRequest:request error:&executeFetchError] lastObject];
if (executeFetchError) {
NSLog(@"[%@, %@] error looking up user with id: %i with error: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), [uniqueUserId intValue], [executeFetchError localizedDescription]);
} else if (!user) {
user = [NSEntityDescription insertNewObjectForEntityForName:@"TZUser"
inManagedObjectContext:context];
}
return user;
}
Solution 2:
From IOS 9 there is a new way to handle unique constraints.
You define the unique attributes in the data model.
You need to set a managed context merge policy "Merge policy singleton objects that define standard ways to handle conflicts during a save operation" NSErrorMergePolicy is the default,This policy causes a save to fail if there are any merge conflicts.
- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
[_managedObjectContext setMergePolicy:NSOverwriteMergePolicy];
return _managedObjectContext;
}
The various option are discussed at Apple Ducumentation Merge Policy
It is answered nicely here Zachary Orr's Answer
and he has kindly also created a blogpost and sample code.
Sample Code
Blog Post
The most challenging part is to get the data Model attributes editable.The Secret is to left click and then right click, after you have clicked the + sign to add a constraint.
Solution 3:
I've decided to use the validate<key>:error:
method to check if there is already a Managed Object with the specific value of <key>
. An error is raised if this is the case.
For example:
- (BOOL)validateMyAttribute:(id *)value error:(NSError **)error { // Return NO if there is already an object with a myAtribute of value }
Thanks to Martin Cote for his input.
Solution 4:
You could override the setMyAttribute
method (using categories) and ensure uniqueness right there, although this may be expensive:
- (void)setMyAttribute:(id)value
{
NSArray *objects = [self fetchObjectsWithMyValueEqualTo:value];
if( [objects count] > 0 ) // ... throw some exception
[self setValue:value forKey:@"myAttribute"];
}
If you want to make sure that every MyEntity
instance has a distinct myAttribute
value, you can use the objectID
of the NSManagedObject
objects for that matter.