NSFetchRequest not catching objects that have a changed property

淺唱寂寞╮ 提交于 2020-01-14 13:28:11

问题


I have run into a weird problem with CoreData on MacOsX 10.6 using an SQL store. I have an NSManagedObject subclass called Family with attribute name and a relationship personList connected to another NSManagedObject subclass called Person with attribute firstname and inverse relationship family. A Person has only one family, and a family can have several Persons.

Say I have a Family object family pointing to the family 'Doe' with 2 Person (John and Jane) connected to it and I do 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 the 2 persons: Jane and John, with Family name Doe. Now, if I update the Family using its synthesized accessor, in my case:

[family setName:@"Wheat"]

I cannot after get the list of Person using the same fetch request. The results is an [array count] of 0.

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

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

So it is as if the Predicate is not using the updated version of the property name of the family, even though I have the NSFetchRequest set to the defaults (so includesPendingChanges returns YES). That makes no sense to me. It seems that the NSFetchRequest finds the family object, but fails to see that its value family.name has been updated, not saved, and is in the managedObjectContext in memory. Of course, if I save the store, then it works again.

Any idea? I have been through the Mac documentation and cannot see why this would fail.


回答1:


I think the key here is understanding the fetch request. It retrieves data from the persistent store, so clearly, if you did not save to the persistent store, it will not find that data. The situation you describe is entirely logical if you take that into account.

From the Core Data Programming Guide:

You cannot fetch using a predicate based on transient properties (although you can use transient properties to filter in memory yourself). Moreover, there are some interactions between fetching and the type of store—for details, see “Store Types and Behaviors.” To summarize, though, if you execute a fetch directly, you should typically not add Objective-C-based predicates or sort descriptors to the fetch request. Instead you should apply these to the results of the fetch. If you use an array controller, you may need to subclass NSArrayController so you can have it not pass the sort descriptors to the persistent store and instead do the sorting after your data has been fetched.




回答2:


To summarize, I have been testing thoroughly my code and here is how I perceive the limitations of CoreData regarding Fetching and objective-c predicated (ie the dot notation).

If an object has been access by the Objective-C program and if one of its property or relationship has been modified, any NSFetchRequest with a predicate using a dot notation will return the structure of the SQL store, hence the results will be erroneous.

In the case of the trivial Family and Person example, if you have a link to a Family and change its name, any query made on the Person NSEntity cannot include a predicate with the following query item

@"family.name=%@"

It will indeed query using the family name in the SQL store. However, the following query will work after such a change:

@"family=%@"

Indeed, the NSFetchRequest will still retrieve the info in the store, but since the structure has not changed, it will replace the objects retrieved by those in Memory, so a subsequent test to [family name] will return the updated name.

With care, you can use nested Predicate such as:

@"person.family.name=%@"

As long as you can guarantee that all the objects that have the property person, have not their family altered, nor their name altered. If it's not the case, then you can at best call

@"person.family=%@"

Or if you can't guarantee that all the Family objects are untouched, only

@"person=%@"

Of course, an alternative is to systematically SAVE: the NSManagedObjects to the persistent store every time you make any change, so all properties are updated and then all the above notations would work. There are times however when you do want to prevent savings and force the customer to change it's document only if he wishes (think about Word, Excel, Picture tools, etc..). Hope this is of help.




回答3:


If by "using the same fetch request", you mean using the very same instance of the fetch request that you constructed the first time, then this is no surprise. The predicate you applied is "family.name = Doe". Once the family's name is "Wheat", the fetch request's predicate no longer matches it, because "Wheat" != "Doe".

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

If by "using the same fetch request", you mean using a different fetch request constructed using the same code, well, then I would think about @Mundi's answer.



来源:https://stackoverflow.com/questions/7128211/nsfetchrequest-not-catching-objects-that-have-a-changed-property

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!