NSFetchRequest does not capture objects that have a modified property

I am having a weird issue with CoreData on MacOsX 10.6 using SQL repository. I have a subclass of NSManagedObject called Family with the name attribute and the personList relationship is associated with another NSManagedObject subclass called Person with the firstname attribute and the inverse Family relationship. A Person has only one Family , and a Family can have several Person s.

Let's say I have a Family Family object that points to the "Doe" family with 2 Person (John and Jane) connected to it, and I make the following request:

 NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease]; [request setEntity:[NSEntityDescription entityForName:@"Person" inManagedObjectContext:managedObjectContext]]; [request setPredicate:[NSPredicate predicateWithFormat:@"family.name=%@",[family name]]]; NSArray *array = [managedObjectContext executeFetchRequest:request error:&error]; 

I get an array of size 2 with two people: Jane and John, with the last name Dow. Now, if I update a family using its synthesized accessor, in my case:

 [family setName:@"Wheat"] 

I cannot get a list of Person using the same select query. The result is [array count] of 0 .

If I change the predicate to the next line, it works again:

 [request setPredicate:[NSPredicate predicateWithFormat:@"family=%@",family]]; 

So, as if Predicate is not using the updated version of the family property name, even if I have NSFetchRequest set to the default value (therefore includesPendingChanges returns YES). It makes no sense to me. It looks like NSFetchRequest finds the Family object, but does not see that its family.name value has family.name updated, not saved, and is in managedObjectContext in memory. Of course, if I save the store, it works again.

Any idea? I went through the Mac documentation and cannot understand why this will happen.

+4
source share
3 answers

I think the key here is understanding the query for the selection. It retrieves data from persistent storage, so if you have not saved to persistent storage, it will not find this data. The situation that you describe is completely logical, given this.

In the Master Data Programming Guide:

You cannot get using a predicate based on transient properties (although you can use transient properties to filter in memory yourself). In addition, there are some interactions between the selection and the type of storage - for more details, see "Types and behavior of the store." to summarize, however, if you fetch directly, you should usually not add Objective-C predicates or sort the descriptors for the fetch request. Instead, you should apply them to the results of the selection. If you use an array controller, you may need to subclass NSArrayController so that you can not pass sort descriptors to persistent storage, and instead, sorting is done after your data has been retrieved.

+4
source

To summarize, I tested my code carefully, and this is how I see CoreData's limitations regarding Fetching and objective-c predicated (i.e., point notation).

If an object was accessible by objective-c, and if one of its properties or relationships was changed, any NSFetchRequest with a predicate using dot notation will return the SQL storage structure, so the results will be erroneous.

In the case of the trivial example Family and Personality , if you have a link to Family and change its name , any request made in Person NSEntity cannot include a predicate with the following request element

@ "family.name =% @"

It will indeed request the use of the family name in the SQL repository. However, after such a change, the following query will work:

@ "family =% @"

In fact, NSFetchRequest will still retrieve information in the repository, but since the structure has not changed, it will replace the objects received by those stored in memory, so a subsequent test on [last name] will return the updated name.

With care, you can use a nested Predicate, for example:

@ "person.family.name =% @"

While you can guarantee that all objects that have the person property have not changed their family , but have not changed their name , if this is not so, then you can call at best

@ "person.family =% @"

Or if you cannot guarantee that all Family objects are intact, only

@ "person =% @"

Of course, the alternative is to systematically SAVE: NSManagedObjects in persistent storage every time you make any changes, so all properties are updated, and then all the above entries will work. However, there are times when you want to prevent savings and make the client change his document only if he wants to (think about Word, Excel, drawing tools, etc.). Hope this helps.

+2
source

If โ€œusing the same fetch requestโ€, you mean using the same instance of the fetch request that you created for the first time, then this is not surprising. The predicate you applied is "family.name = Doe". As soon as the surname is "Wheat", the query query predicate no longer matches it, because "Wheat"! = "Dow."

To get a family after changing its name, you need to create a new instance of NSFetchRequest using the predicate corresponding to the new family.

If "using the same fetch request", you mean using another fetch request built using the same code, well, then I would think about @Mundi's answer.

0
source

All Articles