Core Data NSSQLiteStoreType problem
-
Hi, all.
I am developing a (non-document based) Core Data app and am facing
a problem with saving data in NSSQLiteStoreType.
The app has a subclass of NSManagedObject and can add to-many
relationship
through a custom accessor.
@interface AClass : NSManagedObject
{
}
- (void) addRelation: (NSManagedObject *) aManagedObject;
@end
- (void) addRelation: (NSManagedObject *) aManagedObject
{
NSSet * changedObjects = [[NSSet alloc] initWithObjects:
&aManagedObject count:1];
[self willChangeValueForKey: @"relation"
withSetMutation: NSKeyValueUnionSetMutation
usingObjects: changedObjects];
[[self primitiveValueForKey: @"relation"] addObject: aManagedObject];
[self didChangeValueForKey: @"relation"
withSetMutation: NSKeyValueUnionSetMutation
usingObjects: changedObjects];
[changedObjects release];
}
The custom to-many accessor is the same code introduced in Listing 4
of Managed Object Accessor Methods in Core Data Programming Guide.
In my code, I add managed objects with this accessor and the objects
are added and the to-many relation are established correctly.
But once I save the data and close the app then restart it again,
the objects themselves remain there but the relations of some objects
disappear. (Not all, but some. The relation is not transient.)
I was using NSSQLiteStoreType and when I changed it to NSXMLStoreType
or NSBinaryStoreType, there was no problem and all the relations
remained
after the app was closed and restarted. All the other codes were the
same.
Just the behavior of NSSQLiteStoreType was different.
I wonder why and when the relations once established disappear, only
when
I use NSSQLiteStoreType. Does the type need some extra code the other
types
don't need?
I am using Xcode 3.0 on Leopard.
Thank you. -
On Nov 10, 2007, at 11:18 PM, <chataka...> wrote:
> I am developing a (non-document based) Core Data app and am facing
> a problem with saving data in NSSQLiteStoreType.
>
> The app has a subclass of NSManagedObject and can add to-many
> relationship
> through a custom accessor.
> But once I save the data and close the app then restart it again,
> the objects themselves remain there but the relations of some objects
> disappear.
Describe the relationship in more detail. Specifically, what does its
inverse look like? If it's missing an inverse, or has a to-one
inverse instead of a to-many inverse, that could easily explain what
you're seeing; the implementation of your custom -addRelationship:
method isn't the problem.
That's not to say your -addRelationship: method is entirely correct.
If you're going to implement accessor methods for to-many
relationships, you need to do so in a fashion that's compliant with
Key-Value Coding. Otherwise you run the risk of accidentally
implementing something that matches up with what KVC expects, as -
addRelationship: does, and your results may also be unpredictable.
For Core Data, that means the accessor methods for to-many
relationships need to follow this naming pattern -- which is the
standard naming pattern for set KVC:
For adding & removing one object from the relationship:
- (void)add<Key>Object:(NSManagedObject *)object;
- (void)remove<Key>Object:(NSManagedObject *)object;
For adding & removing (union & minus) sets of objects to & from the
relationship:
- (void)add<Key>:(NSSet *)objects;
- (void)remove<Key>:(NSSet *)objects;
For intersecting sets of objects (optional) with what's in the
relationship:
- (void)intersect<Key>:(NSSet *)objects;
For getting & setting the whole relationship at once (optional):
- (NSSet *)<key>;
- (void)set<Key>:(NSSet *)objects;
This should be documented in the Key-Value Coding Programming Guide;
it's also described in detailed comments in the <Foundation/
NSKeyValueCoding.h> header file, as part of the comments for the -
[NSObject(NSKeyValueCoding) mutableSetValueForKey:] method. And it
goes without saying that your relationship names for to-many
relationships should generally be plural. :)
What this gets you is that code outside your class can just say
(assuming your relationship's name is "items")
NSMutableSet *myItems = [myObject mutableSetValueForKey:@"items"];
and then perform manipulations on myItems (e.g. -addObject:, -
unionSet:, etc.) and it will modify the relationship through your
methods automatically.
-- Chris -
Chris,
Thank you for your response.
> Describe the relationship in more detail. Specifically, what does
> its inverse look like? If it's missing an inverse, or has a to-one
> inverse instead of a to-many inverse, that could easily explain what
> you're seeing;
It doesn't have any inverse relationship. One entity(A) has a to-many
relationship
to another entity(B), but B doesn't have any relationship to A.
I added B to A with the method and A had Bs before I closed the app.
Then when I restart the app, some As have lost all Bs, while other As
who
haven't lost Bs have all Bs. All or nothing.
But if having no inverse relationship is a problem, I suppose the
behaviors of
NSXMLStoreType and NSBinaryStoreType are the same.
In my case, only NSSQLiteStoreType has this problem.
> For Core Data, that means the accessor methods for to-many
> relationships need to follow this naming pattern -- which is the
> standard naming pattern for set KVC:
Thank you, I corrected the method names.
-Chataka -
> It doesn't have any inverse relationship. One entity(A) has a to-many
> relationship to another entity(B), but B doesn't have any
> relationship to A.
That's illegal. If you try to build this on Leopard, you should
receive a lot of warnings. Add the inverse relationship.
There's more in the archives about this.
- Ben


