Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
240 views
in Technique[技术] by (71.8m points)

objective c - Does every Core Data Relationship have to have an Inverse?

Let's say I have two Entity classes: SocialApp and SocialAppType

In SocialApp I have one Attribute: appURL and one Relationship: type.

In SocialAppType I have three Attributes: baseURL, name and favicon.

The destination of the SocialApp relationship type is a single record in SocialAppType.

As an example, for multiple Flickr accounts, there would be a number of SocialApp records, with each record holding a link to a person's account. There would be one SocialAppType record for the "Flickr" type, that all SocialApp records would point to.

When I build an application with this schema, I get a warning that there is no inverse relationship between SocialAppType and SocialApp.

 /Users/username/Developer/objc/TestApp/TestApp.xcdatamodel:SocialApp.type: warning: SocialApp.type -- relationship does not have an inverse

Do I need an inverse, and why?

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Apple documentation has an great example that suggest a situation where you might have problems by not having an inverse relationship. Let's map it into this case.

Assume you modeled it as follows: enter image description here

Note you have a to-one relationship called "type", from SocialApp to SocialAppType. The relationship is non-optional and has a "deny" delete rule.

Now consider the following:

SocialApp *socialApp;
SocialAppType *appType;
// assume entity instances correctly instantiated

[socialApp setSocialAppType:appType];
[managedObjectContext deleteObject:appType];
BOOL saved = [managedObjectContext save:&error];

What we expect is to fail this context save since we have set the delete rule as Deny while relationship is non optional.

But here the save succeeds.

The reason is that we haven't set an inverse relationship. Because of that, the socialApp instance does not get marked as changed when appType is deleted. So no validation happens for socialApp before saving (it assumes no validation needed since no change happened). But actually a change happened. But it doesn't get reflected.

If we recall appType by

SocialAppType *appType = [socialApp socialAppType];

appType is nil.

Weird, isn't it? We get nil for a non-optional attribute?

So you are in no trouble if you have set up the inverse relationship. Otherwise you have to do force validation by writing the code as follows.

SocialApp *socialApp;
SocialAppType *appType;
// assume entity instances correctly instantiated

[socialApp setSocialAppType:appType];
[managedObjectContext deleteObject:appType];

[socialApp setValue:nil forKey:@"socialAppType"]
BOOL saved = [managedObjectContext save:&error];

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...