Re: Core Data : calling validation in awakeFromInsert problem ?
Re: Core Data : calling validation in awakeFromInsert problem ?
- Subject: Re: Core Data : calling validation in awakeFromInsert problem ?
- From: mmalcolm crawford <email@hidden>
- Date: Mon, 5 Sep 2005 12:07:49 -0700
On Sep 5, 2005, at 9:42 AM, Eric Morand wrote:
I have a managed object with one property named "name". This
property is a string. I want this property to be unique in the
managed context of the object, so I've implemented
"validateName..." method in my managed object subclass (see code
below).
Next, I want new objects inserted into the context to have a name
set to a validated one (that means : unique). So I have implemented
"awakeFromInsert..." method in my subclass that set the name
property to a valid one.
[...]
Here is the code for my custom class (implementation only, there is
nothing of interest in the header) :
]...]
- (void)awakeFromInsert
{
[...]
NSString * validName = nil;
NSString * defaultName = [NSString
stringWithString:@"TestObjectName"];
validName = defaultName;
int index = 0;
while ( ![self validateValue:&validName forKey:@"name"
error:nil] )
{
index++;
validName = [defaultName stringByAppendingFormat:@" (%d)",
index];
}
[self setName:validName];
}
- (BOOL)validateName: (id *)valueRef error:(NSError **)outError
{
NSPredicate * predicate = [NSPredicate
predicateWithFormat:@"name == %@", *valueRef];
NSEntityDescription * entityDescription = [NSEntityDescription
entityForName:@"TestObject" inManagedObjectContext:[self
managedObjectContext]];
NSFetchRequest * fetchRequest = [[[NSFetchRequest alloc] init]
autorelease];
[fetchRequest setEntity:entityDescription];
[fetchRequest setPredicate:predicate];
NSArray * results = [[self managedObjectContext]
executeFetchRequest:fetchRequest error:nil];
return ( [results count] < 1 ) || ( [results objectAtIndex:0]
== self );
}
@end
I'm using a simple interface to test the insertion process : in
fact it is the standard interface created automatically when alt-
dragging the object from Xcode to IB - one table view, 3 buttons
(Fetch, Add, Remove), a text field to enter name and a search
field. Then, the problems begin : when I click on the add button,
TWO objects are added to the table view !
I'm not sure if this is a bug (I'll follow up) but it's because
you're executing a fetch (whose results will include self) before the
insertion has completed. You can sidestep this by setting the name
after awakeFromInsert:
- (void)awakeFromInsert
{
[super awakeFromInsert];
[self performSelector:@selector(setUniqueName) withObject:nil
afterDelay:0];
}
There are several issues with the remainder of the awakeFromInsert
code (now moved to the new method) and the validation method:
- (void)setUniqueName
{
NSString * defaultName = @"TestObjectName"; // no need for
stringWithString:
NSString * validName = defaultName; // no need for two assignments
int index = 0;
while ( ![self validateValue:&validName forKey:@"name" error:nil] )
{
index++;
validName = [defaultName stringByAppendingFormat:@" (%d)",
index];
}
[self setName:validName];
}
- (BOOL)validateName: (id *)valueRef error:(NSError **)outError
{
/*
Check (SELF != %@) in fetch; use 'LIKE' not '==' for string comparison
*/
NSPredicate * predicate = [NSPredicate
predicateWithFormat:@"(SELF != %@) AND (name LIKE %@)", self,
*valueRef];
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
/*
Use self's entity -- no need to use NSEntityDescription method to
retrieve (also avoids hard-wiring entity name)
*/
[fetchRequest setEntity:[self entity]];
[fetchRequest setPredicate:predicate];
/*
Should check for error
*/
NSArray * results = [[self managedObjectContext]
executeFetchRequest:fetchRequest error:nil];
[fetchRequest release];
return ( [results count] < 1 );
}
And do you think I'm using the right process to validate my name
property and mak sure my object are inserted with valid name ?
This approach will be very inefficient for anything but data sets
where there is little likelihood of name collisions -- you have to do
an additional fetch for every collision. It's not clear what your
goal is here. If you're simply wanting to set temporary distinct
names (like window titles) for small numbers of objects, this would
probably be OK. If these will be permanent values for an ever-
increasing number of objects, then you'll need a different approach...
mmalc
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden