How to Validate CoreData attribute value for uniqueness
How to Validate CoreData attribute value for uniqueness
- Subject: How to Validate CoreData attribute value for uniqueness
- From: Rick Aurbach <email@hidden>
- Date: Sat, 30 Aug 2014 15:58:02 -0400
- Acceptlanguage: en-US
- Thread-topic: How to Validate CoreData attribute value for uniqueness
Have you thought about a different approach?
Since most of the digits have interpreted meanings, how about offering an alternative way to specifying the catalogID — namely by a dialog which lets the user specify each of the attributes which make up the catalogID (by using some sort of list selection technique; popup menu, radio button group, list, etc). Then, everything except for the “free” digits will be COMPUTABLE. You can then implement whatever strategy you want for calculating the “free” digits (such as a checksum, an index value, etc).
The result is that the user will NOT enter the catalogID, but will instead enter the unique information from which the catalogID is calculated. This should eliminate most errors (except, of course, for the user mis-entering the attribute information).
The final check would be to do a simple fetch on the existing database using the newly-constructed catalogID. If the newly-constructed catalogID is (correctly) unique, the fetch will return nil. A non-nil result means that there is a duplicate.
Does this sound useful in your environment??
Cheers,
Rick Aurbach
Aurbach & Associates, Inc.
On Aug 30, 2014, at 2:00 PM, email@hidden wrote:
> Date: Sat, 30 Aug 2014 13:58:34 +0300
> From: Motti Shneor <email@hidden>
> To: email@hidden
> Subject: How to Validate CoreData attribute value for uniqueness
> Message-ID: <email@hidden>
> Content-Type: text/plain; charset=us-ascii
>
> Hello everyone. Many discussions address this in many development forums. I read them all, and was frustrated NOTHING of the suggested solutions actually worked. Apple's documentation adds insult to injury, completely ignoring such a common need for any real-world Core-Data modeled application.
>
> I have an entity "Species" with a numerical attribute "catalogID" which has "human" meaning (every digit will tell something about the species, plus some free digits). Different species entities must have unique catalog IDs much like social security number for people, or ISBN for books. I have no more than few hundred "Species" entities, and they have many attributes and relations.
>
> My wish is simple. To emit an error dialog when a user tries to use an existing ID when creating a new species in the UI (source/detail window), or when trying to edit the ID of an existing species, changing it to a value taken for another species.
>
> After much reading, I implemented KVC validation (validate<key>:error:) in my NSManagedObject subclass "PMSpecies" like thus:
>
> -(BOOL)validateCatalogID:(id *)ioValue error:(NSError * __autoreleasing *)outError {
> // Prepare optimized static request to only fetch all species catalogID's for reuse every time we validate the edited species catalogID.
> static NSFetchRequest *allSpeciesIDsFetchRequest = nil;
> if (allSpeciesIDsFetchRequest == nil) {
> allSpeciesIDsFetchRequest = [NSFetchRequest fetchRequestWithEntityName:[[self entity] name]];
> [allSpeciesIDsFetchRequest setPropertiesToFetch:@[ @"catalogID" ]];
> [allSpeciesIDsFetchRequest setResultType: NSDictionaryResultType];
> }
> NSArray *allSpecies = [self.managedObjectContext executeFetchRequest:allSpeciesIDsFetchRequest error:nil];
> NSArray *allCatalogIDs = [allSpecies valueForKeyPath:@"catalogID"];
> if ([allCatalogIDs containsObject:*ioValue]) {
> if (outError != NULL) {
> NSDictionary *userInfoDict = @{ NSLocalizedDescriptionKey : [NSString stringWithFormat:NSLocalizedString(@"The ID %@ is already taken by another species. Please use a unique ID.", NULL), *ioValue] };
> *outError = [[NSError alloc] initWithDomain:@"Model Validation" code:eExistingCatalogID userInfo:userInfoDict];
> }
> return NO;
> }
> return YES; // valid ID
> }
>
>
> I was happy enough to see that the bound NSTextField in the UI now behaved correctly, and emitted error upon adding/updating a species with a non-unique ID. However - the moment I try to save my context to the persistent store, I receive hundreds of "uniqueness" errors for every species.
>
> I saw that the above validation method was called for every species on every save, and in those calls, my "fetch" indeed finds one occurrence of the ID --- the actual NSManagedObject's! which is OK.
>
> So this kind of validation can't work because it is used in 2 different situations - BEFORE the value was set to the attribute, and AFTER is was set (upon saving the context). But in this method, I don't have a "context" meaning, I don't know what kind of validation is this.
>
>
> I tried to implement instead the validateForInsert: and validateForUpate: methods, but then the UI remains stupid, and only when the user actually saves the document (long after closing the "Species" window) he receives strange validation errors. In these implementations, I detect violations by finding 2 or more of the same ID - not just one as the above.
>
> Apple CoreData Programming Guide tells you the following:
>
> NSManagedObject provides consistent hooks for validating property and inter-property values. You typically should not override validateValue:forKey:error:, instead you should implement methods of the form validate<Key>:error:, as defined by the NSKeyValueCoding protocol. If you want to validate inter-property values, you can override validateForUpdate: and/or related validation methods.
>
> But there is absolutely nothing about inter-entity validation, such as value uniqueness, value ordering dependency upon previous entities like serial IDs or any cross-entity validation.
>
> Can anyone shed light on the subject?
>
> At my current situation, I would gladly settle on a UI-only validation (meaning, something that would validate a text field upon end-edit-session, but I don't know how to hook this on a bound-to-model field either.
>
> Please help...
>
> Motti Shneor
> ---
> It is impossible to make anything foolproof, because fools are so ingenious.
> - Mark Twain
>
> Make something fool-proof, and only fools will use it.
> - My own addition
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden