Is it possible to model relationships between entities that are defined in separate NSManagedObjectModels if the entities are always used within an NSManagedObjectModel that is created by merging the relevant models?
For example, say model 1 defines an entity Foo
with relationship (one-to-one) toBar
and that model 2 defines an entity Bar
with a relationship (one-to-one) toFoo
. I will build a CoreData stack using -[NSManagedObjectModel mergedModelFromModels]
, merging model 1 and model 2. Is there any way to define these relationships either in the data modeler or programatically so that they behave as if they were in-model relationships?
Neither model 1 nor model 2 will be loadable at run time unless they're well-formed — that is, unless the toBar
and toFoo
relationships have destinations. Furthermore, if model 1 and model 2 have identically-named models, you won't be able to create a merged model from them; they will not be coalesced, they will collide, which is an error.
However, you can use the NSManagedObjectModel
API manually to load each model and create a new model by hand that contains entities from both. The NSEntityDescription
and NSPropertyDescription
classes (and its subclasses) do implement the NSCopying
protocol so in most cases you should just be able to copy properties over from each component model to your overall model.
Furthermore, the NS*Description
classes all support a userInfo
dictionary that you can edit in Xcode's data modeling tool, which you can use to do things like tag the destination of a relationship as a stand-in. For example, in model 1 you could have a Bar
entity with a userInfo
key MyRealEntity
and check for that when creating your merged model, as a signal to use the real entity instead.
You'll also want to put stand-in inverse relationships to your stand-in entities; these will be replaced with real inverses after merging. You don't have to totally replicate your stand-in entities in all models, though; you only need the inverse relationships used in your real model in a stand in entity.
Thus if your real Foo
has a name
attribute, and your real Bar has a kind
attribute, your stand-in Foo
and Bar
won't need those, just stand-in toBar
and toFoo
relationships.
Here's some code demonstrating what I'm talking about:
- (NSManagedObjectModel *)mergeModelsReplacingDuplicates:(NSArray *)models {
NSManagedObjectModel *mergedModel = [[[NSManagedObjectModel alloc] init] autorelease];
// General strategy: For each model, copy its non-placeholder entities
// and add them to the merged model. Placeholder entities are identified
// by a MyRealEntity key in their userInfo (which names their real entity,
// though their mere existence is sufficient for the merging).
NSMutableArray *mergedModelEntities = [NSMutableArray arrayWithCapacity:0];
for (NSManagedObjectModel *model in models) {
for (NSEntityDescription *entity in [model entities]) {
if ([[entity userInfo] objectForKey:@"MyRealEntity"] == nil) {
NSEntityDescription *newEntity = [entity copy];
[mergedModelEntities addObject:newEntity];
[newEntity release];
} else {
// Ignore placeholder.
}
}
}
[mergedModel setEntities:mergedModelEntities];
return mergedModel;
}
This works because copying of NS*Description
objects in Core Data is by-name rather than by-value with respect to a relationship's destination entity and inverse (and to an entity's subentities as well). Thus while a model is mutable — that is, before it's set as the model for an NSPersistentStoreCoordinator
— you can use tricks like this to break your model into multiple models.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With