Support creating a temporary object (MOC = nil) with +createInContext: #546

Closed
airdrummingfool opened this Issue Aug 22, 2013 · 12 comments

6 participants

@airdrummingfool

Using +createInContext: and passing nil results in an assertion error. Creating the entity using the standard initWithEntity:insertIntoManagedObjectContext: and passing nil for the context works, and returns an instance of the entity that is not persisted on any context. This is useful for creating temporary objects that do not get saved or show up in fetches.

+createInContext calls +insertInManagedObjectContext: (which is on the entity generated with Mogenerator), which performs an assert on the MOC and then calls [NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:].

@tonyarnold

This is included in MagicalRecord 2.3.0 and higher.

@tonyarnold tonyarnold closed this Apr 8, 2014
@lukedixon

Hi Tony,

I'm using the head version of MR and I'm attempting to use the MR_createEntityInContext: method to create disconnected temporary objects, like so:

ManagedObject *managedObject = [ManagedObject MR_createEntityInContext:nil];
manageObject.title = @"Title";

And saving like so:

[[NSManagedObjectContext MR_defaultContext] insertObject:managedObject];
[[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];

However, when I check the sql database the title hasn't been saved. Am I doing something wrong? Any help would be greatly appreciated.

Thanks

@smyrgl

Don't use MR_createEntityInContext:nil, use MR_createEntity instead. Here is the full process:

ManagedObject *managedObject = [ManagedObject MR_createEntity];
manageObject.title = @"Title";
[[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfAndWait];

You don't need to do MR_saveToPersistentStoreAndWait unless you really need the data saved synchronously to the persistent store which defeats the purpose of the two context stack that MagicalRecord uses.

@lukedixon

Thanks for the prompt response. However, won't using MR_createEntity connect that object to the default context and therefore be persistent and not temporary? What happens if I decide not to save the object to the context?

@ketzusaka
@lukedixon

I've tried doing this:

NSManagedObject *managedObject = [NSManagedObject MR_createEntityInContext:[NSManagedObjectContext MR_newContext]];
    [managedObject setTitle:@"Foo"];

    if ([managedObject managedObjectContext]) {
        [[managedObject managedObjectContext] MR_saveOnlySelfAndWait];
    }

    [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];

However the NSManagedObject isn't saved to the persistent store, any ideas? I'm using v2.3.0-beta.2 btw, could this be causing issues?

@ketzusaka
@tonyarnold

@lukedixon your original approach looks sound to me, with one change:

ManagedObject *managedObject = [ManagedObject MR_createEntityInContext:nil];
manageObject.title = @"Title";

// And saving like so:

[[NSManagedObjectContext MR_rootSavingContext] insertObject:managedObject];
[[NSManagedObjectContext MR_rootSavingContext] MR_saveOnlySelfAndWait];

So one of the changes I'm working on for MagicalRecord 2.3 and higher is that I'd like to start treating MR_defaultContext as read only — it's good for observing and binding to your UI, but it's best not to use it to write changes — what you're seeing is a bug, but it's not necessarily incorrect behaviour down the line. Try performing the same tasks on MR_rootSavingContext and everything should work.

A simpler, cleaner approach might be:

ManagedObject *managedObject = [ManagedObject MR_createEntityInContext:nil];
manageObject.title = @"Title";

// Now save:

[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
    [localContext insertObject:managedObject];
}];
@tonyarnold tonyarnold added this to the 2.3.0 milestone Apr 23, 2014
@tonyarnold tonyarnold self-assigned this Apr 23, 2014
@lukedixon

@tonyarnold thanks, however I'm still having the problem of the missing title in the persistent store.

This doesn't work (in persistent store; title == NULL):

ManagedObject *managedObject = [ManagedObject MR_createEntityInContext:nil];
manageObject.title = @"Title";

// Now save:
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
    [localContext insertObject:managedObject];
}];

However this does (in persistent store; title == "Title"):

ManagedObject *managedObject = [ManagedObject MR_createEntityInContext:nil];
manageObject.title = @"Title";

// Now save:
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
    [localContext insertObject:managedObject];
    manageObject.title = @"Title";
}];

Any thoughts? Could this be a beta bug?

EDIT:

So, I tried the first example and it works (thanks a million). So the working code is:

ManagedObject *managedObject = [ManagedObject MR_createEntityInContext:nil];
manageObject.title = @"Title";

// And saving like so:

[[NSManagedObjectContext MR_rootSavingContext] insertObject:managedObject];
[[NSManagedObjectContext MR_rootSavingContext] MR_saveOnlySelfAndWait];

As you say though, the second example is cleaner therefore it would be interesting to know why that isn't working as expected.

Thanks again!

@tonyarnold

It's entirely possible that it is — I'm going to need to work up a test to check.

@lukedixon

Thanks @tonyarnold - if I find anything else that will help I'll post it here.

@marcmatta

Hi @tonyarnold,

Problem still persists and only works as described by lukedixon. It would be a lot cleaner to write

ManagedObject *managedObject = [ManagedObject MR_createEntityInContext:nil];
manageObject.title = @"Title";

// Now save:
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
    [localContext insertObject:managedObject];
}]

Any plans to fix this bug in the near future?

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment